Add software

This commit is contained in:
RocketGod
2022-09-22 09:26:57 -07:00
parent fee0ab05fd
commit 957ea3d712
4511 changed files with 1943182 additions and 0 deletions

View File

@ -0,0 +1,263 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/adc_lld.c
* @brief LPC43xx ADC subsystem low level driver source.
*
* @addtogroup ADC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief ADC0 driver identifier.
*/
#if LPC43XX_ADC_USE_ADC0 || defined(__DOXYGEN__)
ADCDriver ADCD0;
#endif
/**
* @brief ADC1 driver identifier.
*/
#if LPX43XX_ADC_USE_ADC1 || defined(__DOXYGEN__)
ADCDriver ADCD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#if LPC43XX_ADC_USE_ADC0
static const adc_resources_t adc0_resources = {
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1U << 0) },
.branch = { .cfg = &LPC_CCU1->CLK_APB3_ADC0_CFG, .stat = &LPC_CCU1->CLK_APB3_ADC0_STAT },
.reset = { .output_index = 40 },
.interrupt = { .irq = ADC0_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_ADC0_IRQ_PRIORITY) },
};
#endif /* LPC43XX_ADC_USE_ADC0 */
#if LPC43XX_ADC_USE_ADC1
static const adc_resources_t adc1_resources = {
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1U << 0) },
.branch = { .cfg = &LPC_CCU1->CLK_APB3_ADC1_CFG, .stat = &LPC_CCU1->CLK_APB3_ADC1_STAT },
.reset = { .output_index = 41 },
.interrupt = { .irq = ADC1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_ADC1_IRQ_PRIORITY) },
};
#endif /* LPC43XX_ADC_USE_ADC1 */
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief ADC ISR service routine.
*
* @param[in] adcp pointer to the @p ADCDriver object
* @param[in] flags pre-shifted content of the ISR register
*/
static void adc_lld_serve_interrupt(ADCDriver *adcp) {
/* TODO: Implement */
uint32_t dr[8];
uint32_t stat = adcp->adc->STAT;
for(size_t i=0; i<8; i++) {
if( stat & 1 ) {
dr[i] = adcp->adc->DR[i];
}
stat >>= 1;
}
if( adcp->grpp ) {
} else {
/* Conversion is stopped. Ignore */
/* TODO: Read conversion registers to clear interrupt? */
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if LPC43XX_ADC_USE_ADC0 || defined(__DOXYGEN__)
/**
* @brief ADC0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(ADC0_IRQHandler) {
CH_IRQ_PROLOGUE();
adc_lld_serve_interrupt(&ADCD0);
CH_IRQ_EPILOGUE();
}
#endif
#if LPC43XX_ADC_USE_ADC1 || defined(__DOXYGEN__)
/**
* @brief ADC1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(ADC1_IRQHandler) {
CH_IRQ_PROLOGUE();
adc_lld_serve_interrupt(&ADCD1);
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level ADC driver initialization.
*
* @notapi
*/
void adc_lld_init(void) {
#if LPC43XX_ADC_USE_ADC0
/* Driver initialization.*/
adcObjectInit(&ADCD0);
/* TODO: Implement */
ADCD0.adc = LPC_ADC0;
ADCD0.resources = &adc0_resources;
#endif /* LPC43XX_ADC_USE_ADC0 */
#if LPC43XX_ADC_USE_ADC1
/* Driver initialization.*/
adcObjectInit(&ADCD1);
/* TODO: Implement */
ADCD1.adc = LPC_ADC1;
ADCD1.resources = &adc1_resources;
#endif /* LPC43XX_ADC_USE_ADC1 */
}
/**
* @brief Configures and activates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start(ADCDriver *adcp) {
if (adcp->state == ADC_STOP) {
/* Enables the peripheral.*/
base_clock_enable(&adcp->resources->base);
branch_clock_enable(&adcp->resources->branch);
peripheral_reset(&adcp->resources->reset);
interrupt_enable(&adcp->resources->interrupt);
/* Configures the peripheral.*/
adcp->adc->CR =
(0x00 << 0)
| (adcp->config->cr_clkdiv << 8)
| (0 << 16)
| (adcp->config->cr_clks << 17)
| (1 << 21)
| (0 << 24)
| (0 << 27)
;
}
}
/**
* @brief Deactivates the ADC peripheral.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop(ADCDriver *adcp) {
if (adcp->state == ADC_READY) {
/* Resets the peripheral.*/
/* Reset START to 0x0, power down. */
adcp->adc->CR =
(0x00 << 0)
| (adcp->config->cr_clkdiv << 8)
| (0 << 16)
| (adcp->config->cr_clks << 17)
| (0 << 21)
| (0 << 24)
| (0 << 27)
;
/* Disables the peripheral.*/
interrupt_disable(&adcp->resources->interrupt);
peripheral_reset(&adcp->resources->reset);
branch_clock_disable(&adcp->resources->branch);
base_clock_disable(&adcp->resources->base);
}
}
/**
* @brief Starts an ADC conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
const ADCConversionGroup *grpp = adcp->grpp;
adcp->adc->CR =
(grpp->cr_sel << 0)
| (adcp->config->cr_clkdiv << 8)
| (0 << 16)
| (adcp->config->cr_clks << 17)
| (1 << 21)
| (1 << 24)
| (0 << 27)
;
}
/**
* @brief Stops an ongoing conversion.
*
* @param[in] adcp pointer to the @p ADCDriver object
*
* @notapi
*/
void adc_lld_stop_conversion(ADCDriver *adcp) {
adcp->adc->CR =
(0x00 << 0)
| (adcp->config->cr_clkdiv << 8)
| (0 << 16)
| (adcp->config->cr_clks << 17)
| (1 << 21)
| (0 << 24)
| (0 << 27)
;
}
#endif /* HAL_USE_ADC */
/** @} */

View File

@ -0,0 +1,279 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/adc_lld.h
* @brief LPC43xx ADC subsystem low level driver header.
*
* @addtogroup ADC
* @{
*/
#ifndef _ADC_LLD_H_
#define _ADC_LLD_H_
#if HAL_USE_ADC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @name Absolute Maximum Ratings
* @{
*/
/**
* @brief Minimum ADC clock frequency.
*/
#define LPC43XX_ADCCLK_MAX 4500000
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief ADC0 driver enable switch.
* @details If set to @p TRUE the support for ADC0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC43XX_ADC_USE_ADC0) || defined(__DOXYGEN__)
#define LPC43XX_ADC_USE_ADC0 FALSE
#endif
/**
* @brief ADC1 driver enable switch.
* @details If set to @p TRUE the support for ADC1 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC43XX_ADC_USE_ADC1) || defined(__DOXYGEN__)
#define LPC43XX_ADC_USE_ADC1 FALSE
#endif
#if 0
/**
* @brief ADC0 DMA interrupt priority level setting.
*/
#if !defined(LPC43XX_ADC_ADC0_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_ADC_ADC0_DMA_IRQ_PRIORITY 7
#endif
/**
* @brief ADC1 DMA interrupt priority level setting.
*/
#if !defined(LPC43XX_ADC_ADC1_DMA_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_ADC_ADC1_DMA_IRQ_PRIORITY 7
#endif
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !LPC43XX_ADC_USE_ADC0 && !LPC43XX_ADC_USE_ADC1
#error "ADC driver activated but no ADC peripheral assigned"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Structure used for ADC configuration.
*/
typedef LPC_ADCx_Type* ADC_TypeDef;
/**
* @brief ADC sample data type.
*/
typedef uint16_t adcsample_t;
/**
* @brief Channels number in a conversion group.
*/
typedef uint16_t adc_channels_num_t;
/**
* @brief Possible ADC failure causes.
* @note Error codes are architecture dependent and should not relied
* upon.
*/
typedef enum {
ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */
ADC_ERR_OVERFLOW = 1 /**< ADC overflow condition. */
} adcerror_t;
/**
* @brief Type of a structure representing an ADC driver.
*/
typedef struct ADCDriver ADCDriver;
/**
* @brief ADC notification callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] buffer pointer to the most recent samples data
* @param[in] n number of buffer rows available starting from @p buffer
*/
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
/**
* @brief ADC error callback type.
*
* @param[in] adcp pointer to the @p ADCDriver object triggering the
* callback
* @param[in] err ADC error code
*/
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
/**
* @brief Conversion group configuration structure.
* @details This implementation-dependent structure describes a conversion
* operation.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
bool_t circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
adccallback_t end_cb;
/**
* @brief Error callback or @p NULL.
*/
adcerrorcallback_t error_cb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR sel field initialization data.
*/
uint8_t cr_sel;
} ADCConversionGroup;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
/**
* @brief ADC CR clkdiv field initialization data.
*/
uint8_t cr_clkdiv;
/**
* @brief ADC CR clks field initialization data.
*/
uint8_t cr_clks;
} ADCConfig;
/**
* @brief Structure representing an ADC driver.
*/
struct ADCDriver {
/**
* @brief Driver state.
*/
adcstate_t state;
/**
* @brief Current configuration data.
*/
const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
Thread *thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
ADC_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Pointer to the ADCx registers block.
*/
ADC_TypeDef adc;
/**
* @brief Pointer to the non-peripheral ADC resources.
*/
const adc_resources_t * resources;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC43XX_ADC_USE_ADC0 && !defined(__DOXYGEN__)
extern ADCDriver ADCD0;
#endif
#if LPC43XX_ADC_USE_ADC1 && !defined(__DOXYGEN__)
extern ADCDriver ADCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void adc_lld_init(void);
void adc_lld_start(ADCDriver *adcp);
void adc_lld_stop(ADCDriver *adcp);
void adc_lld_start_conversion(ADCDriver *adcp);
void adc_lld_stop_conversion(ADCDriver *adcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_ADC */
#endif /* _ADC_LLD_H_ */
/** @} */

View File

@ -0,0 +1,316 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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 local definitions. */
/*===========================================================================*/
#if LPC43XX_GPT_USE_TIMER0
static const timer_resources_t timer0_resources = {
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER0_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER0_STAT },
.reset = { .output_index = 32 },
.interrupt = { .irq = TIMER0_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER0_IRQ_PRIORITY) },
};
#endif /* LPC43XX_GPT_USE_TIMER0 */
#if LPC43XX_GPT_USE_TIMER1
static const timer_resources_t timer1_resources = {
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER1_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER1_STAT },
.reset = { .output_index = 33 },
.interrupt = { .irq = TIMER1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER1_IRQ_PRIORITY) },
};
#endif /* LPC43XX_GPT_USE_TIMER1 */
#if LPC43XX_GPT_USE_TIMER2
static const timer_resources_t timer2_resources = {
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER2_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER2_STAT },
.reset = { .output_index = 34 },
.interrupt = { .irq = TIMER2_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER2_IRQ_PRIORITY) },
};
#endif /* LPC43XX_GPT_USE_TIMER3 */
#if LPC43XX_GPT_USE_TIMER3
static const timer_resources_t timer3_resources = {
.branch = { .cfg = &LPC_CCU1->CLK_M4_TIMER3_CFG, .stat = &LPC_CCU1->CLK_M4_TIMER3_STAT },
.reset = { .output_index = 35 },
.interrupt = { .irq = TIMER3_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC43XX_GPT_TIMER3_IRQ_PRIORITY) },
};
#endif /* LPC43XX_GPT_USE_TIMER3 */
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief GPTD1 driver identifier.
*/
#if LPC43XX_GPT_USE_TIMER0 || defined(__DOXYGEN__)
GPTDriver GPTD1;
#endif
/**
* @brief GPTD2 driver identifier.
*/
#if LPC43XX_GPT_USE_TIMER1 || defined(__DOXYGEN__)
GPTDriver GPTD2;
#endif
/**
* @brief GPTD3 driver identifier.
*/
#if LPC43XX_GPT_USE_TIMER2 || defined(__DOXYGEN__)
GPTDriver GPTD3;
#endif
/**
* @brief GPTD4 driver identifier.
*/
#if LPC43XX_GPT_USE_TIMER3 || 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 = (1U << 0); /* 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 LPC43XX_GPT_USE_TIMER0
/**
* @brief TIMER0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Timer0_IRQHandler) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_GPT_USE_TIMER0 */
#if LPC43XX_GPT_USE_TIMER1
/**
* @brief TIMER1 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Timer1_IRQHandler) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD2);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_GPT_USE_TIMER1 */
#if LPC43XX_GPT_USE_TIMER2
/**
* @brief TIMER2 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Timer2_IRQHandler) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD3);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_GPT_USE_TIMER2 */
#if LPC43XX_GPT_USE_TIMER3
/**
* @brief TIMER3 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(Timer3_IRQHandler) {
CH_IRQ_PROLOGUE();
gpt_lld_serve_interrupt(&GPTD4);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_GPT_USE_TIMER3 */
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level GPT driver initialization.
*
* @notapi
*/
void gpt_lld_init(void) {
#if LPC43XX_GPT_USE_TIMER0
/* Driver initialization.*/
gptObjectInit(&GPTD1);
GPTD1.tmr = LPC_TIMER0;
GPTD1.resources = &timer0_resources;
#endif /* LPC43XX_GPT_USE_TIMER0 */
#if LPC43XX_GPT_USE_TIMER1
/* Driver initialization.*/
gptObjectInit(&GPTD2);
GPTD2.tmr = LPC_TIMER1;
GPTD2.resources = &timer1_resources;
#endif /* LPC43XX_GPT_USE_TIMER1 */
#if LPC43XX_GPT_USE_TIMER2
/* Driver initialization.*/
gptObjectInit(&GPTD3);
GPTD3.tmr = LPC_TIMER2;
GPTD3.resources = &timer2_resources;
#endif /* LPC43XX_GPT_USE_TIMER2 */
#if LPC43XX_GPT_USE_TIMER3
/* Driver initialization.*/
gptObjectInit(&GPTD4);
GPTD4.tmr = LPC_TIMER3;
GPTD4.resources = &timer3_resources;
#endif /* LPC43XX_GPT_USE_TIMER3 */
}
/**
* @brief Configures and activates the GPT peripheral.
*
* @param[in] gptp pointer to the @p GPTDriver object
*
* @notapi
*/
void gpt_lld_start(GPTDriver *gptp) {
if (gptp->state == GPT_STOP) {
/* Enables the peripheral.*/
branch_clock_enable(&gptp->resources->branch);
peripheral_reset(&gptp->resources->reset);
interrupt_enable(&gptp->resources->interrupt);
}
/* Timer configuration.*/
gptp->tmr->PR = gptp->config->pr;
gptp->tmr->IR = (1U << 0);
gptp->tmr->MCR = 0; /* Disable all interrupt sources */
gptp->tmr->TCR = 0; /* Disable counter */
}
/**
* @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) {
/* Resets the peripheral.*/
gptp->tmr->MCR = 0;
gptp->tmr->TCR = 0;
interrupt_disable(&gptp->resources->interrupt);
peripheral_reset(&gptp->resources->reset);
branch_clock_disable(&gptp->resources->branch);
}
}
/**
* @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,251 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief GPTD1 driver enable switch.
* @details If set to @p TRUE the support for GPTD1 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC43XX_GPT_USE_TIMER0) || defined(__DOXYGEN__)
#define LPC43XX_GPT_USE_TIMER0 FALSE
#endif
/**
* @brief GPTD2 driver enable switch.
* @details If set to @p TRUE the support for GPTD2 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC43XX_GPT_USE_TIMER1) || defined(__DOXYGEN__)
#define LPC43XX_GPT_USE_TIMER1 FALSE
#endif
/**
* @brief GPTD3 driver enable switch.
* @details If set to @p TRUE the support for GPTD3 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC43XX_GPT_USE_TIMER2) || defined(__DOXYGEN__)
#define LPC43XX_GPT_USE_TIMER2 FALSE
#endif
/**
* @brief GPTD4 driver enable switch.
* @details If set to @p TRUE the support for GPTD4 is included.
* @note The default is @p TRUE.
*/
#if !defined(LPC43XX_GPT_USE_TIMER3) || defined(__DOXYGEN__)
#define LPC43XX_GPT_USE_TIMER3 FALSE
#endif
/**
* @brief GPTD1 interrupt priority level setting.
*/
#if !defined(LPC43XX_GPT_TIMER0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_GPT_TIMER0_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD2 interrupt priority level setting.
*/
#if !defined(LPC43XX_GPT_TIMER1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_GPT_TIMER1_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD3 interrupt priority level setting.
*/
#if !defined(LPC43XX_GPT_TIMER2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_GPT_TIMER2_IRQ_PRIORITY 7
#endif
/**
* @brief GPTD4 interrupt priority level setting.
*/
#if !defined(LPC43XX_GPT_TIMER3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC43XX_GPT_TIMER3_IRQ_PRIORITY 7
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if LPC43XX_GPT_USE_TIMER0 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC43XX_GPT_TIMER0_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIMER0"
#endif
#if LPC43XX_GPT_USE_TIMER1 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC43XX_GPT_TIMER1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIMER1"
#endif
#if LPC43XX_GPT_USE_TIMER2 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC43XX_GPT_TIMER2_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIMER2"
#endif
#if LPC43XX_GPT_USE_TIMER3 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC43XX_GPT_TIMER3_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to TIMER3"
#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.*/
/**
* @brief Prescale counter value.
*/
uint32_t pr;
} 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 Pointer to the TIMER registers block.
*/
LPC_TIMER_Type *tmr;
/**
* @brief Pointer to the non-peripheral Timer resources.
*/
const timer_resources_t * resources;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Changes the interval of GPT peripheral.
* @details This function changes the interval of a running GPT unit.
* @pre The GPT unit must have been activated using @p gptStart().
* @pre The GPT unit must have been running in continuous mode using
* @p gptStartContinuous().
* @post The GPT unit interval is changed to the new value.
* @note The function has effect immediately.
*
* @param[in] gptp pointer to a @p GPTDriver object
* @param[in] interval new cycle time in timer ticks
* @notapi
*/
#define gpt_lld_change_interval(gptp, interval) \
((gptp)->tmr->MR[0] = ((interval) - 1))
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC43XX_GPT_USE_TIMER0 && !defined(__DOXYGEN__)
extern GPTDriver GPTD1;
#endif
#if LPC43XX_GPT_USE_TIMER1 && !defined(__DOXYGEN__)
extern GPTDriver GPTD2;
#endif
#if LPC43XX_GPT_USE_TIMER2 && !defined(__DOXYGEN__)
extern GPTDriver GPTD3;
#endif
#if LPC43XX_GPT_USE_TIMER3 && !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,590 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/i2c_lld.c
* @brief LPC43xx I2C subsystem low level driver source.
*
* @addtogroup I2C
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_I2C || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/** @brief START transmitted.*/
#define I2C_START 0x08
/** @brief Repeated START transmitted.*/
#define I2C_REPEAT_START 0x10
/** @brief Arbitration Lost.*/
#define I2C_ARBITRATION_LOST 0x38
/** @brief Bus errors.*/
#define I2C_BUS_ERROR 0x00
/** @brief SLA+W transmitted with ACK response.*/
#define I2C_MASTER_TX_ADDR_ACK 0x18
/** @brief SLA+W transmitted with NACK response.*/
#define I2C_MASTER_TX_ADDR_NACK 0x20
/** @brief DATA transmitted with ACK response.*/
#define I2C_MASTER_TX_DATA_ACK 0x28
/** @brief DATA transmitted with NACK response.*/
#define I2C_MASTER_TX_DATA_NACK 0x30
/** @brief SLA+R transmitted with ACK response.*/
#define I2C_MASTER_RX_ADDR_ACK 0x40
/** @brief SLA+R transmitted with NACK response.*/
#define I2C_MASTER_RX_ADDR_NACK 0x48
/** @brief DATA received with ACK response.*/
#define I2C_MASTER_RX_DATA_ACK 0x50
/** @brief DATA received with NACK response.*/
#define I2C_MASTER_RX_DATA_NACK 0x58
/** @brief Send I2C NACK. */
#define I2C_NACK 0
/** @brief Send I2C ACK. */
#define I2C_ACK 1
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/** @brief I2C0 driver identifier.*/
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
I2CDriver I2CD0;
#endif
/** @brief I2C1 driver identifier.*/
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
I2CDriver I2CD1;
#endif
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
#if LPC43XX_I2C_USE_I2C0
static const i2c_resources_t i2c0_resources = {
.base = { .clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1) },
.branch = { .cfg = &LPC_CCU1->CLK_APB1_I2C0_CFG, .stat = &LPC_CCU1->CLK_APB1_I2C0_STAT },
.reset = { .output_index = 48 },
};
#endif /* LPC43XX_I2C_USE_I2C0 */
#if LPC43XX_I2C_USE_I2C1
static const i2c_resources_t i2c1_resources = {
.base = { .clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 0) },
.branch = { .cfg = &LPC_CCU1->CLK_APB3_I2C1_CFG, .stat = &LPC_CCU1->CLK_APB3_I2C1_STAT },
.reset = { .output_index = 49 },
};
#endif /* LPC43XX_I2C_USE_I2C1 */
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/**
* @brief Wakes up the waiting thread.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] msg wakeup message
*
* @notapi
*/
#define wakeup_isr(i2cp, msg) { \
chSysLockFromIsr(); \
if ((i2cp)->thread != NULL) { \
Thread *tp = (i2cp)->thread; \
(i2cp)->thread = NULL; \
tp->p_u.rdymsg = (msg); \
chSchReadyI(tp); \
} \
chSysUnlockFromIsr(); \
}
/**
* @brief Set clock speed.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
static void i2c_periph_set_clock(I2C_TypeDef dp, uint16_t high_count, uint16_t low_count) {
dp->SCLH = (uint32_t)high_count;
dp->SCLL = (uint32_t)low_count;
}
/* Peripheral functions */
static void i2c_periph_enable(I2C_TypeDef dp) {
dp->CONSET =
I2C_CONSET_I2EN
;
}
static void i2c_periph_disable(I2C_TypeDef dp) {
dp->CONCLR =
I2C_CONCLR_AAC
| I2C_CONCLR_SIC
| I2C_CONCLR_STAC
| I2C_CONCLR_I2ENC
;
}
/*
static void i2c_periph_clear_start(I2C_TypeDef dp) {
dp->CONCLR =
I2C_CONCLR_STAC
;
}
*/
static void i2c_periph_clear_all(I2C_TypeDef dp) {
dp->CONCLR =
I2C_CONCLR_SIC
| I2C_CONCLR_STAC
;
}
static uint_fast8_t i2c_periph_status(I2C_TypeDef dp) {
return dp->STAT;
}
/*
static void i2c_periph_start(I2C_TypeDef dp) {
dp->CONSET = I2C_CONSET_STA;
dp->CONCLR = I2C_CONCLR_SIC;
}
*/
static void i2c_periph_stop(I2C_TypeDef dp) {
dp->CONSET = I2C_CONSET_STO | I2C_CONSET_AA;
dp->CONCLR = I2C_CONCLR_SIC;
}
static void i2c_periph_transfer_byte(I2C_TypeDef dp, int ack) {
dp->CONSET = (ack == I2C_NACK) ? 0 : I2C_CONSET_AA;
dp->CONCLR = I2C_CONCLR_SIC | ((ack == I2C_NACK) ? I2C_CONCLR_AAC : 0);
}
/*
static void i2c_periph_transmit_byte(I2C_TypeDef dp, uint_fast8_t byte) {
dp->DAT = byte;
i2c_periph_transfer_byte(dp, I2C_ACK);
}
*/
static uint_fast8_t i2c_periph_read_byte(I2C_TypeDef dp) {
return dp->DAT & 0xff;
}
/* LLD functions */
static void i2c_lld_abort_operation(I2CDriver *i2cp) {
i2c_periph_stop(i2cp->i2c);
i2cp->state = I2C_STOP;
}
static bool_t i2c_lld_tx_not_done(I2CDriver *i2cp) {
return i2cp->txbytes > 0;
}
static bool_t i2c_lld_rx_not_done(I2CDriver *i2cp) {
return i2cp->rxbytes > 0;
}
static bool_t i2c_lld_rx_last_byte(I2CDriver *i2cp) {
return i2cp->rxbytes == 1;
}
/**
* @brief Handling of stalled I2C transactions.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
static void i2c_lld_safety_timeout(void *p) {
I2CDriver *i2cp = (I2CDriver *)p;
chSysLockFromIsr();
if (i2cp->thread) {
Thread *tp = i2cp->thread;
i2c_lld_abort_operation(i2cp);
i2cp->thread = NULL;
tp->p_u.rdymsg = RDY_TIMEOUT;
chSchReadyI(tp);
}
chSysUnlockFromIsr();
}
/**
* @brief I2C shared ISR code.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
I2C_TypeDef dp = i2cp->i2c;
/* TODO: Likely that bugs remain around clearing STA/STO flags */
switch (i2c_periph_status(dp)) {
case I2C_START: /* 0x08 */
case I2C_REPEAT_START: /* 0x10 */
//i2c_periph_clear_start(dp);
dp->DAT = i2cp->addr_r;
dp->CONCLR = I2C_CONCLR_STAC | I2C_CONCLR_SIC;
//i2c_periph_transmit_byte(dp, i2cp->addr_r);
break;
case I2C_MASTER_TX_ADDR_ACK: /* 0x18 */
/* Previous state 0x08 or 0x10, slave address + write has been
* transmitted. ACK has been received. The first data byte will
* be transmitted, and an ACK bit will be received.
*/
/* fall through */
case I2C_MASTER_TX_DATA_ACK: /* 0x28 */
if (i2c_lld_tx_not_done(i2cp)) {
//i2c_periph_transmit_byte(dp, i2cp->txbuf[i2cp->txidx++]);
dp->DAT = *i2cp->txbuf++;
i2cp->txbytes--;
dp->CONCLR = I2C_CONCLR_SIC;
} else {
if (i2c_lld_rx_not_done(i2cp)) {
dp->CONSET = I2C_CONSET_STA;
dp->CONCLR = I2C_CONCLR_SIC;
//i2c_periph_start(dp);
} else {
dp->CONSET = I2C_CONSET_STO;
dp->CONCLR = I2C_CONCLR_SIC;
//i2c_periph_stop(dp);
wakeup_isr(i2cp, RDY_OK);
}
}
break;
case I2C_MASTER_RX_DATA_ACK: /* 0x50 */
*i2cp->rxbuf++ = i2c_periph_read_byte(dp);
i2cp->rxbytes--;
/* fall through */
case I2C_MASTER_RX_ADDR_ACK: /* 0x40 */
if (i2c_lld_rx_last_byte(i2cp)) {
i2c_periph_transfer_byte(dp, I2C_NACK);
} else {
i2c_periph_transfer_byte(dp, I2C_ACK);
}
break;
case I2C_MASTER_RX_DATA_NACK: /* 0x58 */
*i2cp->rxbuf++ = i2c_periph_read_byte(dp);
i2cp->rxbytes--;
i2c_periph_stop(dp);
wakeup_isr(i2cp, RDY_OK);
/* fall through */
case I2C_MASTER_TX_ADDR_NACK: /* 0x20 */
/* Slave address and R/W transmitted, NACK received (no response) */
case I2C_MASTER_TX_DATA_NACK: /* 0x30 */
/* Data transmitted, NACK received (no response) */
case I2C_MASTER_RX_ADDR_NACK: /* 0x48 */
/* Slave address and R/W transmitted, NACK received (no response) */
i2cp->errors |= I2CD_ACK_FAILURE;
break;
case I2C_ARBITRATION_LOST: /* 0x38 */
i2cp->errors |= I2CD_ARBITRATION_LOST;
break;
case I2C_BUS_ERROR: /* 0x00 */
i2cp->errors |= I2CD_BUS_ERROR;
break;
default:
i2c_periph_stop(dp);
wakeup_isr(i2cp, RDY_RESET);
break;
}
if (i2cp->errors != I2CD_NO_ERROR) {
i2c_periph_stop(dp);
wakeup_isr(i2cp, RDY_RESET);
}
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
#if defined(LPC43XX_M4)
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(I2C0_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_lld_serve_event_interrupt(&I2CD0);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_I2C_USE_I2C0 */
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(I2C1_IRQHandler) {
CH_IRQ_PROLOGUE();
i2c_lld_serve_event_interrupt(&I2CD1);
CH_IRQ_EPILOGUE();
}
#endif /* LPC43XX_I2C_USE_I2C1 */
#endif
#if defined(LPC43XX_M0)
CH_IRQ_HANDLER(I2C0_Or_I2C1_IRQHandler) {
CH_IRQ_PROLOGUE();
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
if( LPC_I2C0->CONSET & I2C_CONSET_SI ) i2c_lld_serve_event_interrupt(&I2CD0);
#endif
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
if( LPC_I2C1->CONSET & I2C_CONSET_SI ) i2c_lld_serve_event_interrupt(&I2CD1);
#endif
CH_IRQ_EPILOGUE();
}
#endif
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Low level I2C driver initialization.
*
* @notapi
*/
void i2c_lld_init(void) {
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
i2cObjectInit(&I2CD0);
I2CD0.thread = NULL;
I2CD0.i2c = LPC_I2C0;
I2CD0.resources = &i2c0_resources;
#endif /* LPC43XX_I2C_USE_I2C0 */
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
i2cObjectInit(&I2CD1);
I2CD1.thread = NULL;
I2CD1.i2c = LPC_I2C1;
I2CD1.resources = &i2c1_resources;
#endif /* LPC43XX_I2C_USE_I2C1 */
}
/**
* @brief Configures and activates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
void i2c_lld_start(I2CDriver *i2cp) {
I2C_TypeDef dp = i2cp->i2c;
/* TODO: Reset peripheral, enable clocks? */
base_clock_enable(&i2cp->resources->base);
branch_clock_enable(&i2cp->resources->branch);
peripheral_reset(&i2cp->resources->reset);
i2c_periph_set_clock(dp, i2cp->config->high_count, i2cp->config->low_count);
i2c_periph_enable(dp);
i2c_periph_clear_all(dp);
#if defined(LPC43XX_M4)
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
if (&I2CD0 == i2cp) {
nvicEnableVector(I2C0_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4_I2C_I2C0_IRQ_PRIORITY));
}
#endif /* LPC43XX_I2C_USE_I2C0 */
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
if (&I2CD1 == i2cp) {
nvicEnableVector(I2C1_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M4_I2C_I2C1_IRQ_PRIORITY));
}
#endif /* LPC43XX_I2C_USE_I2C1 */
#endif
#if defined(LPC43XX_M0)
nvicEnableVector(I2C0_OR_I2C1_IRQn, CORTEX_PRIORITY_MASK(LPC43XX_M0_I2C_I2C0_OR_I2C1_IRQ_PRIORITY));
#endif
}
/**
* @brief Deactivates the I2C peripheral.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
void i2c_lld_stop(I2CDriver *i2cp) {
I2C_TypeDef dp = i2cp->i2c;
/* If not in stopped state then disables the I2C clock.*/
if (i2cp->state != I2C_STOP) {
i2c_lld_abort_operation(i2cp);
#if LPC43XX_I2C_USE_I2C0 || defined(__DOXYGEN__)
if (&I2CD0 == i2cp) {
#if defined(LPC43XX_M4)
nvicDisableVector(I2C0_IRQn);
#endif
#if defined(LPC43XX_M0)
#if LPC43XX_I2C_USE_I2C1
if( I2CD1.state == I2C_STOP ) {
#endif
// TODO: This won't work if the I2C peripherals are split between cores!
nvicDisableVector(I2C0_OR_I2C1_IRQn);
#if LPC43XX_I2C_USE_I2C1
}
#endif
#endif
}
#endif /* LPC43XX_I2C_USE_I2C0 */
#if LPC43XX_I2C_USE_I2C1 || defined(__DOXYGEN__)
if (&I2CD1 == i2cp) {
#if defined(LPC43XX_M4)
nvicDisableVector(I2C1_IRQn);
#endif
#if defined(LPC43XX_M0)
#if LPC43XX_I2C_USE_I2C0
if( I2CD0.state == I2C_STOP ) {
#endif
// TODO: This won't work if the I2C peripherals are split between cores!
nvicDisableVector(I2C0_OR_I2C1_IRQn);
#if LPC43XX_I2C_USE_I2C0
}
#endif
#endif
}
#endif /* LPC43XX_I2C_USE_I2C1 */
i2c_periph_disable(dp);
peripheral_reset(&i2cp->resources->reset);
branch_clock_disable(&i2cp->resources->branch);
base_clock_disable(&i2cp->resources->base);
}
}
static msg_t i2c_lld_master_start(I2CDriver *i2cp, uint_fast8_t addr_r,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
I2C_TypeDef dp = i2cp->i2c;
VirtualTimer vt;
/* Resetting error flags for this transfer.*/
i2cp->errors = I2CD_NO_ERROR;
/* Global timeout for the whole operation.*/
if (timeout != TIME_INFINITE)
chVTSetI(&vt, timeout, i2c_lld_safety_timeout, (void *)i2cp);
i2cp->addr_r = addr_r;
i2cp->txbuf = txbuf;
i2cp->txbytes = txbytes;
i2cp->rxbuf = rxbuf;
i2cp->rxbytes = rxbytes;
/* Atomic check on the timer in order to make sure that a timeout didn't
happen outside the critical zone.*/
if ((timeout != TIME_INFINITE) && !chVTIsArmedI(&vt))
return RDY_TIMEOUT;
dp->CONCLR =
I2C_CONCLR_AAC
| I2C_CONCLR_SIC
| I2C_CONCLR_STAC
;
dp->CONSET = I2C_CONSET_STA;
/* Waits for the operation completion or a timeout.*/
i2cp->thread = chThdSelf();
chSchGoSleepS(THD_STATE_SUSPENDED);
if ((timeout != TIME_INFINITE) && chVTIsArmedI(&vt))
chVTResetI(&vt);
return chThdSelf()->p_u.rdymsg;
}
/**
* @brief Transmits data via the I2C bus as master.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address
* @param[in] txbuf pointer to the transmit buffer
* @param[in] txbytes number of bytes to be transmitted
* @param[out] rxbuf pointer to the receive buffer
* @param[in] rxbytes number of bytes to be received
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* @return The operation status.
* @retval RDY_OK if the function succeeded.
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a
* timeout the driver must be stopped and restarted
* because the bus is in an uncertain state</b>.
*
* @notapi
*/
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
return i2c_lld_master_start(i2cp, (addr << 1) | 0, txbuf, txbytes, rxbuf, rxbytes, timeout);
}
/**
* @brief Receives data via the I2C bus as master.
*
* @param[in] i2cp pointer to the @p I2CDriver object
* @param[in] addr slave device address
* @param[out] rxbuf pointer to the receive buffer
* @param[in] rxbytes number of bytes to be received
* @param[in] timeout the number of ticks before the operation timeouts,
* the following special values are allowed:
* - @a TIME_INFINITE no timeout.
* .
* @return The operation status.
* @retval RDY_OK if the function succeeded.
* @retval RDY_RESET if one or more I2C errors occurred, the errors can
* be retrieved using @p i2cGetErrors().
* @retval RDY_TIMEOUT if a timeout occurred before operation end. <b>After a
* timeout the driver must be stopped and restarted
* because the bus is in an uncertain state</b>.
*
* @notapi
*/
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout) {
return i2c_lld_master_start(i2cp, (addr << 1) | 1, NULL, 0, rxbuf, rxbytes, timeout);
}
#endif /* HAL_USE_I2C */
/** @} */

View File

@ -0,0 +1,245 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/i2c_lld.h
* @brief LPC43xx I2C subsystem low level driver header.
*
* @addtogroup I2C
* @{
*/
#ifndef _I2C_LLD_H_
#define _I2C_LLD_H_
#if HAL_USE_I2C || defined(__DOXYGEN__)
/* I2C peripheral bears a striking resemblence to the AVR I2C peripheral. */
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
#if 0
/** @brief START transmitted.*/
#define I2C_START 0x08
/** @brief Repeated START transmitted.*/
#define I2C_REPEAT_START 0x10
/** @brief Arbitration Lost.*/
#define I2C_ARBITRATION_LOST 0x38
/** @brief Bus errors.*/
#define I2C_BUS_ERROR 0x00
/** @brief SLA+W transmitted with ACK response.*/
#define I2C_MASTER_TX_ADDR_ACK 0x18
/** @brief SLA+W transmitted with NACK response.*/
#define I2C_MASTER_TX_ADDR_NACK 0x20
/** @brief DATA transmitted with ACK response.*/
#define I2C_MASTER_TX_DATA_ACK 0x28
/** @brief DATA transmitted with NACK response.*/
#define I2C_MASTER_TX_DATA_NACK 0x30
/** @brief SLA+R transmitted with ACK response.*/
#define I2C_MASTER_RX_ADDR_ACK 0x40
/** @brief SLA+R transmitted with NACK response.*/
#define I2C_MASTER_RX_ADDR_NACK 0x48
/** @brief DATA received with ACK response.*/
#define I2C_MASTER_RX_DATA_ACK 0x50
/** @brief DATA received with NACK response.*/
#define I2C_MASTER_RX_DATA_NACK 0x58
#endif
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief I2C0 driver enable switch.
* @details If set to @p TRUE the support for I2C0 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC43XX_I2C_USE_I2C0) || defined(__DOXYGEN__)
#define LPC43XX_I2C_USE_I2C0 FALSE
#endif
/**
* @brief I2C1 driver enable switch.
* @details If set to @p TRUE the support for I2C1 is included.
* @note The default is @p FALSE.
*/
#if !defined(LPC43XX_I2C_USE_I2C1) || defined(__DOXYGEN__)
#define LPC43XX_I2C_USE_I2C1 FALSE
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Structure used for I2C configuration.
*/
typedef LPC_I2Cx_Type* I2C_TypeDef;
/**
* @brief Type representing I2C address.
*/
typedef uint8_t i2caddr_t;
/**
* @brief I2C Driver condition flags type.
*/
typedef uint8_t i2cflags_t;
/**
* @brief Driver configuration structure.
* @note Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/**
* @brief Specifies the I2C clock frequency and duty cycle.
*/
uint16_t high_count;
uint16_t low_count;
} I2CConfig;
/**
* @brief Structure representing an I2C driver.
*/
struct I2CDriver {
/**
* @brief Driver state.
*/
i2cstate_t state;
/**
* @brief Current configuration data.
*/
const I2CConfig *config;
/**
* @brief Error flags.
*/
i2cflags_t errors;
#if I2C_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the bus.
*/
Mutex mutex;
#elif CH_USE_SEMAPHORES
Semaphore semaphore;
#endif
#endif /* I2C_USE_MUTUAL_EXCLUSION */
#if defined(I2C_DRIVER_EXT_FIELDS)
I2C_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
* @brief Thread waiting for I/O completion.
*/
Thread *thread;
/**
* @brief Address of slave device.
*/
uint8_t addr_r;
/**
* @brief Pointer to the buffer with data to send.
*/
const uint8_t *txbuf;
/**
* @brief Number of bytes of data to send.
*/
size_t txbytes;
/**
* @brief Pointer to the buffer to put received data.
*/
uint8_t *rxbuf;
/**
* @brief Number of bytes of data to receive.
*/
size_t rxbytes;
/**
* @brief Pointer to the I2Cx registers block.
*/
I2C_TypeDef i2c;
/**
* @brief Pointer to the non-peripheral I2C resources.
*/
const i2c_resources_t * resources;
};
/**
* @brief Type of a structure representing an I2C driver.
*/
typedef struct I2CDriver I2CDriver;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Get errors from I2C driver.
*
* @param[in] i2cp pointer to the @p I2CDriver object
*
* @notapi
*/
#define i2c_lld_get_errors(i2cp) ((i2cp)->errors)
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
#if LPC43XX_I2C_USE_I2C0
extern I2CDriver I2CD0;
#endif
#if LPC43XX_I2C_USE_I2C1
extern I2CDriver I2CD1;
#endif
#endif /* !defined(__DOXYGEN__) */
#ifdef __cplusplus
extern "C" {
#endif
void i2c_lld_init(void);
void i2c_lld_start(I2CDriver *i2cp);
void i2c_lld_stop(I2CDriver *i2cp);
msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
const uint8_t *txbuf, size_t txbytes,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
uint8_t *rxbuf, size_t rxbytes,
systime_t timeout);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_I2C */
#endif /* _I2C_LLD_H_ */
/** @} */

View File

@ -0,0 +1,68 @@
/*
Copyright (C) 2018 Jared Boone, ShareBrained Technology
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.
*/
#include "hal.h"
void peripheral_reset(const peripheral_reset_t* const reset) {
const size_t register_index = (reset->output_index >> 5) & 1;
const size_t bit_shift = reset->output_index & 0x1f;
const uint32_t mask = (1U << bit_shift);
LPC_RGU->RESET_CTRL[register_index] = mask | (~LPC_RGU->RESET_ACTIVE_STATUS[register_index]);
while((LPC_RGU->RESET_ACTIVE_STATUS[register_index] & mask) == 0);
}
void base_clock_enable(const base_clock_regs_t* const base) {
if( base->clk->PD ) {
base->clk->AUTOBLOCK = 1;
//base->clk->CLK_SEL = ?;
base->clk->PD = 0;
}
}
void base_clock_disable(const base_clock_regs_t* const base) {
if( !base->clk->PD ) {
// Are all branch clocks switched off?
// NOTE: Field stat must be valid memory address.
// NOTE: Field stat_mask is zero if there's no means to check if a base clock is in use.
if( (*base->stat & base->stat_mask) == 0 ) {
base->clk->PD = 1;
//base->clk->CLK_SEL = IRC?;
}
}
}
void branch_clock_enable(const branch_clock_regs_t* const branch) {
if( !branch->stat->RUN ) {
branch->cfg->AUTO = 1;
branch->cfg->RUN = 1;
while(!branch->stat->RUN);
}
}
void branch_clock_disable(const branch_clock_regs_t* const branch) {
if( branch->stat->RUN ) {
branch->cfg->RUN = 0;
while(branch->stat->RUN);
}
}
void interrupt_enable(const interrupt_config_t* const interrupt) {
nvicEnableVector(interrupt->irq, interrupt->priority_mask);
}
void interrupt_disable(const interrupt_config_t* const interrupt) {
nvicDisableVector(interrupt->irq);
}

View File

@ -0,0 +1,273 @@
/*
Copyright (C) 2018 Jared Boone, ShareBrained Technology
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.
*/
#ifndef _LPC43XX_H_
#define _LPC43XX_H_
typedef struct {
LPC_CGU_BASE_CLK_Type* clk;
__I uint32_t* stat;
uint32_t stat_mask;
} base_clock_regs_t;
typedef struct {
LPC_CCU1_CFG_160_Type* cfg;
LPC_CCU_STAT_Type* stat;
} branch_clock_regs_t;
typedef struct {
uint_fast8_t output_index;
} peripheral_reset_t;
typedef struct {
IRQn_Type irq;
uint32_t priority_mask;
} interrupt_config_t;
typedef struct {
uint32_t data;
uint32_t dir;
} gpio_setup_t;
struct scu_config_normal_drive_t {
uint16_t mode;
uint16_t epd;
uint16_t epun;
uint16_t ehs;
uint16_t ezi;
uint16_t zif;
};
struct scu_config_sfsi2c0_t {
uint16_t scl_efp;
uint16_t scl_ehd;
uint16_t scl_ezi;
uint16_t scl_zif;
uint16_t sda_efp;
uint16_t sda_ehd;
uint16_t sda_ezi;
uint16_t sda_zif;
};
struct scu_config_t {
#ifdef __cplusplus
scu_config_t() = delete;
scu_config_t(const scu_config_t&) = delete;
scu_config_t(scu_config_t&) = delete;
constexpr scu_config_t(
uint16_t value
) :
word(value)
{
}
constexpr scu_config_t(
const scu_config_normal_drive_t config
) :
word(
((config.mode & 7) << 0)
| ((config.epd & 1) << 3)
| ((config.epun & 1) << 4)
| ((config.ehs & 1) << 5)
| ((config.ezi & 1) << 6)
| ((config.zif & 1) << 7)
)
{
}
constexpr scu_config_t(
const scu_config_sfsi2c0_t config
) :
word(
((config.scl_efp & 1) << 0)
| ((config.scl_ehd & 1) << 2)
| ((config.scl_ezi & 1) << 3)
| ((config.scl_zif & 1) << 7)
| ((config.sda_efp & 1) << 8)
| ((config.sda_ehd & 1) << 10)
| ((config.sda_ezi & 1) << 11)
| ((config.sda_zif & 1) << 15)
)
{
}
constexpr operator uint32_t() const {
return word;
}
private:
#endif
uint16_t word;
};
#ifndef __cplusplus
typedef struct scu_config_t scu_config_t;
#endif
typedef struct {
uint8_t port;
uint8_t pin;
scu_config_t config;
} scu_setup_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset;
interrupt_config_t interrupt;
} adc_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
} audio_clock_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset;
} gpdma_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset;
} i2c_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset[2];
} i2s_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset;
} motocon_pwm_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch_register_if;
branch_clock_regs_t branch_peripheral;
peripheral_reset_t reset;
interrupt_config_t interrupt;
} sdio_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch;
peripheral_reset_t reset;
} sgpio_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch_register_if;
branch_clock_regs_t branch_peripheral;
peripheral_reset_t reset;
} ssp_resources_t;
typedef struct {
branch_clock_regs_t branch;
peripheral_reset_t reset;
interrupt_config_t interrupt;
} timer_resources_t;
typedef struct {
base_clock_regs_t base;
branch_clock_regs_t branch_register_if;
branch_clock_regs_t branch_peripheral;
peripheral_reset_t reset;
interrupt_config_t interrupt;
} uart_resources_t;
static const base_clock_regs_t base_clock_apb3 = {
.clk = &LPC_CGU->BASE_APB3_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 0),
};
static const base_clock_regs_t base_clock_apb1 = {
.clk = &LPC_CGU->BASE_APB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 1),
};
static const base_clock_regs_t base_clock_spifi = {
.clk = &LPC_CGU->BASE_SPIFI_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 2),
};
static const base_clock_regs_t base_clock_m4 = {
.clk = &LPC_CGU->BASE_M4_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 3),
};
static const base_clock_regs_t base_clock_periph = {
.clk = &LPC_CGU->BASE_PERIPH_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 6),
};
static const base_clock_regs_t base_clock_usb0 = {
.clk = &LPC_CGU->BASE_USB0_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 7),
};
static const base_clock_regs_t base_clock_usb1 = {
.clk = &LPC_CGU->BASE_USB1_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 8),
};
static const base_clock_regs_t base_clock_spi = {
.clk = &LPC_CGU->BASE_SPI_CLK, .stat = &LPC_CCU1->BASE_STAT, .stat_mask = (1 << 9),
};
static const base_clock_regs_t base_clock_uart3 = {
.clk = &LPC_CGU->BASE_UART3_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 1),
};
static const base_clock_regs_t base_clock_uart2 = {
.clk = &LPC_CGU->BASE_UART2_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 2),
};
static const base_clock_regs_t base_clock_uart1 = {
.clk = &LPC_CGU->BASE_UART1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 3),
};
static const base_clock_regs_t base_clock_uart0 = {
.clk = &LPC_CGU->BASE_UART0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 4),
};
static const base_clock_regs_t base_clock_ssp1 = {
.clk = &LPC_CGU->BASE_SSP1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 5),
};
static const base_clock_regs_t base_clock_ssp0 = {
.clk = &LPC_CGU->BASE_SSP0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 6),
};
#ifdef __cplusplus
extern "C" {
#endif
void peripheral_reset(const peripheral_reset_t* const reset);
void base_clock_enable(const base_clock_regs_t* const base);
void base_clock_disable(const base_clock_regs_t* const base);
void branch_clock_enable(const branch_clock_regs_t* const branch);
void branch_clock_disable(const branch_clock_regs_t* const branch);
void interrupt_enable(const interrupt_config_t* const interrupt);
void interrupt_disable(const interrupt_config_t* const interrupt);
#ifdef __cplusplus
}
#endif
#endif /* _LPC43XX_H_ */

View File

@ -0,0 +1,102 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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 templates/pal_lld.c
* @brief PAL subsystem low level driver template.
*
* @addtogroup PAL
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_PAL || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
/**
* @brief LPC43xx I/O ports configuration.
* @details Ports 0 through 8.
*
* @param[in] config the STM32 ports configuration
*
* @notapi
*/
void _pal_lld_init(const PALConfig *config) {
for(size_t i=0; i<8; i++) {
LPC_GPIO->PIN[i] = config->P[i].data;
LPC_GPIO->DIR[i] = config->P[i].dir;
}
for(size_t i=0; i<ARRAY_SIZE(config->SCU); i++) {
LPC_SCU->SFSP[config->SCU[i].port][config->SCU[i].pin] = config->SCU[i].config.word;
}
}
/**
* @brief Pads mode setup.
* @details This function programs a pads group belonging to the same port
* with the specified mode.
*
* @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) {
/* TODO: Handling pull-up, pull-down modes not implemented, as it would
* require a map from GPIO to SCU pins. Not today.
*/
if( mode == PAL_MODE_OUTPUT_PUSHPULL ) {
LPC_GPIO->DIR[port] |= mask;
} else {
LPC_GPIO->DIR[port] &= ~mask;
}
}
#endif /* HAL_USE_PAL */
/** @} */

View File

@ -0,0 +1,386 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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 templates/pal_lld.h
* @brief PAL subsystem low level driver header template.
*
* @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 Generic I/O ports 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 Implementations may extend this structure to contain more,
* architecture dependent, fields.
*/
typedef struct {
/** @brief GPIO setup data.*/
gpio_setup_t P[8];
scu_setup_t SCU[60];
} 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 uint8_t ioportid_t;
/**
* @brief Pad Identifier.
*/
typedef uint8_t iopadid_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 GPIO1 port identifier.
*/
#define IOPORT3 2
#define GPIO2 2
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT4 3
#define GPIO3 3
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT5 4
#define GPIO4 4
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT6 5
#define GPIO5 5
/**
* @brief GPIO1 port identifier.
*/
#define IOPORT7 6
#define GPIO6 6
/**
* @brief GPIO1 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->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->SET[(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->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->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->CLR[(port)] = (bits))
/**
* @brief Toggles 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 XORed on the specified port
*
* @notapi
*/
#define pal_lld_toggleport(port, bits) (LPC_GPIO->NOT[(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) 0
/**
* @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) (void)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 Reads a logical state from an I/O pad.
* @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
* @return The logical state.
* @retval PAL_LOW low logical state.
* @retval PAL_HIGH high logical state.
*
* @notapi
*/
#define pal_lld_readpad(port, pad) \
(LPC_GPIO->B[((port) * 32) + (pad)])
/**
* @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) \
((LPC_GPIO->B[((port) * 32) + (pad)]) = (bit))
/**
* @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->SET[(port)] = 1 << (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->CLR[(port)] = 1 << (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->NOT[(port)] = 1 << (pad))
/**
* @brief Pad mode setup.
* @details This function programs a pad with the specified mode.
* @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.
* @note Programming an unknown or unsupported mode is silently ignored.
*
* @param[in] port port identifier
* @param[in] pad pad number within the port
* @param[in] mode pad mode
*
* @notapi
*/
//#define pal_lld_setpadmode(port, pad, mode)
#if !defined(__DOXYGEN__)
extern const PALConfig pal_default_config;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void _pal_lld_init(const PALConfig *config);
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,249 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC43xx/rtc_lld.c
* @brief RTC low level driver.
*
* @addtogroup RTC
* @{
*/
#include "ch.h"
#include "hal.h"
#if HAL_USE_RTC || defined(__DOXYGEN__)
#include "stdlib.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/**
* @brief RTC driver identifier.
*/
RTCDriver RTCD1;
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
static bool clock_32k768_is_running(void) {
const uint32_t creg0_masked = LPC_CREG->CREG0 & ((1U << 3) | (1U << 2));
const uint32_t creg0_expected = 0;
return (creg0_masked == creg0_expected);
}
static void clock_32k768_init(void) {
// Reset and enable 32.768kHz oscillator
LPC_CREG->CREG0 &= ~((1U << 3) | (1U << 2));
}
static void rtc_enable(LPC_RTC_Type* const rtc) {
/* Enable counter, release internal divider from reset */
rtc->CCR = (rtc->CCR & ~(1U << 1)) | (1U << 0);
}
static void rtc_disable_for_set(LPC_RTC_Type* const rtc) {
/* Disable counter, hold internal divider in reset */
rtc->CCR = (rtc->CCR & ~(1U << 0)) | (1U << 1);
}
static bool rtc_calibration_enabled(LPC_RTC_Type* const rtc) {
return (rtc->CCR & (1U << 4)) == 0;
}
static void rtc_calibration_enable(LPC_RTC_Type* const rtc) {
rtc->CALIBRATION = 0;
rtc->CCR &= ~(1U << 4);
}
#if 0
static void rtc_calibration_set(LPC_RTC_Type* const rtc, const int32_t period) {
rtc->CALIBRATION =
(abs(period) & 0x1ffff)
| ((period < 0) ? 1 : 0);
}
#endif
static void rtc_interrupts_disable(LPC_RTC_Type* const rtc) {
rtc->CIIR = 0;
}
static void rtc_interrupts_clear(LPC_RTC_Type* const rtc) {
rtc->ILR =
(1U << 0)
| (1U << 1)
;
}
static uint_fast8_t timespec_sec(const RTCTime* const timespec) {
return (timespec->tv_time >> 0) & 0x03f;
}
static uint_fast8_t timespec_min(const RTCTime* const timespec) {
return (timespec->tv_time >> 8) & 0x03f;
}
static uint_fast8_t timespec_hrs(const RTCTime* const timespec) {
return (timespec->tv_time >> 16) & 0x01f;
}
static uint_fast8_t timespec_dow(const RTCTime* const timespec) {
return (timespec->tv_time >> 24) & 0x007;
}
static uint_fast8_t timespec_dom(const RTCTime* const timespec) {
return (timespec->tv_date >> 0) & 0x01f;
}
static uint_fast8_t timespec_month(const RTCTime* const timespec) {
return (timespec->tv_date >> 8) & 0x00f;
}
static uint_fast16_t timespec_year(const RTCTime* const timespec) {
return (timespec->tv_date >> 16) & 0xfff;
}
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
/**
* @brief Enable access to registers.
*
* @api
*/
void rtc_lld_init(void){
RTCD1.rtc = LPC_RTC;
/* NOTE: Before enabling RTC, ensure that 32.768kHz clock has been enabled
* for at least two seconds.
*/
if( !clock_32k768_is_running() ) {
clock_32k768_init();
/* NOTE: This will be called while MCU clock is at 12MHz (IRC) */
halPolledDelay(2000 * 12000);
}
/* Disable 32kHz output */
LPC_CREG->CREG0 &= ~(1U << 1);
/* Enable 1kHz output */
LPC_CREG->CREG0 |= (1U << 0);
rtc_interrupts_disable(LPC_RTC);
rtc_interrupts_clear(LPC_RTC);
if( !rtc_calibration_enabled(LPC_RTC) ) {
rtc_calibration_enable(LPC_RTC);
}
rtc_enable(LPC_RTC);
}
/**
* @brief Set current time.
* @note Fractional part will be silently ignored. There is no possibility
* to set it on STM32 platform.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[in] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec) {
LPC_RTC_Type* const rtc = rtcp->rtc;
rtc_disable_for_set(rtc);
rtc->SEC = timespec_sec(timespec);
rtc->MIN = timespec_min(timespec);
rtc->HRS = timespec_hrs(timespec);
rtc->DOW = timespec_dow(timespec);
rtc->DOM = timespec_dom(timespec);
rtc->MONTH = timespec_month(timespec);
rtc->YEAR = timespec_year(timespec);
rtc_enable(rtc);
}
/**
* @brief Get current time.
*
* @param[in] rtcp pointer to RTC driver structure
* @param[out] timespec pointer to a @p RTCTime structure
*
* @api
*/
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec) {
LPC_RTC_Type* const rtc = rtcp->rtc;
/* Read time and date until two consecutive reads return the same values.
*/
do {
timespec->tv_time = rtc->CTIME0;
timespec->tv_date = rtc->CTIME1;
} while( (timespec->tv_time != rtc->CTIME0) || (timespec->tv_date != rtc->CTIME1) );
}
/**
* @brief Get current time in format suitable for usage in FatFS.
*
* @param[in] rtcp pointer to RTC driver structure
* @return FAT time value.
*
* @api
*/
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp) {
RTCTime timespec;
rtc_lld_get_time(rtcp, &timespec);
const int32_t year = (int32_t)timespec_year(&timespec) - 1980;
uint32_t fattime = (year > 0) ? year : 0;
fattime <<= 4;
fattime |= timespec_month(&timespec);
fattime <<= 5;
fattime |= timespec_dom(&timespec);
fattime <<= 5;
fattime |= timespec_hrs(&timespec);
fattime <<= 6;
fattime |= timespec_min(&timespec);
fattime <<= 5;
fattime |= timespec_sec(&timespec) >> 1;
return fattime;
}
#endif /* HAL_USE_RTC */
/** @} */

View File

@ -0,0 +1,110 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
Concepts and parts of this file have been contributed by Uladzimir Pylinsky
aka barthess.
*/
/**
* @file LPC43xx/rtc_lld.h
* @brief RTC low level driver header.
*
* @addtogroup RTC
* @{
*/
#ifndef _RTC_LLD_H_
#define _RTC_LLD_H_
#if HAL_USE_RTC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
typedef LPC_RTC_Type RTC_TypeDef;
/**
* @brief Structure representing an RTC time stamp.
*/
struct RTCTime {
/**
* @brief RTC date register in LPC43xx BCD format.
*/
uint32_t tv_date;
/**
* @brief RTC time register in LPC43xx BCD format.
*/
uint32_t tv_time;
};
/**
* @brief Structure representing an RTC driver.
*/
struct RTCDriver {
/**
* @brief Pointer to the RTC registers block.
*/
RTC_TypeDef* rtc;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if !defined(__DOXYGEN__)
extern RTCDriver RTCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void rtc_lld_init(void);
void rtc_lld_set_time(RTCDriver *rtcp, const RTCTime *timespec);
void rtc_lld_get_time(RTCDriver *rtcp, RTCTime *timespec);
// void rtc_lld_set_alarm(RTCDriver *rtcp,
// rtcalarm_t alarm,
// const RTCAlarm *alarmspec);
// void rtc_lld_get_alarm(RTCDriver *rtcp,
// rtcalarm_t alarm,
// RTCAlarm *alarmspec);
uint32_t rtc_lld_get_time_fat(RTCDriver *rtcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_RTC */
#endif /* _RTC_LLD_H_ */
/** @} */

View File

@ -0,0 +1,234 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/sdc_lld.h
* @brief LPC43xx SDC subsystem low level driver header.
*
* @addtogroup SDC
* @{
*/
#ifndef _SDC_LLD_H_
#define _SDC_LLD_H_
#if HAL_USE_SDC || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @name Configuration options
* @{
*/
/**
* @brief SDC driver enable switch.
* @details If set to @p TRUE the support for SDC1 is included.
*/
#if !defined(LPC_SDC_USE_SDC1) || defined(__DOXYGEN__)
#define LPC_SDC_USE_SDC1 TRUE
#endif
/**
* @brief SDIO interrupt priority level setting.
*/
#if !defined(LPC_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SDC_SDIO_IRQ_PRIORITY 7
#endif
/**
* @brief SDIO read/write descriptor count.
*/
#if !defined(LPC_SDC_SDIO_DESCRIPTOR_COUNT) || defined(__DOXYGEN__)
#define LPC_SDC_SDIO_DESCRIPTOR_COUNT 4
#endif
/** @} */
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if !CORTEX_IS_VALID_KERNEL_PRIORITY(LPC_SDC_SDIO_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to SDIO"
#endif
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of SDIO bus mode.
*/
typedef enum {
SDC_MODE_1BIT = 0,
SDC_MODE_4BIT,
SDC_MODE_8BIT
} sdcbusmode_t;
/**
* @brief Type of card flags.
*/
typedef uint32_t sdcmode_t;
/**
* @brief SDC Driver condition flags type.
*/
typedef uint32_t sdcflags_t;
/**
* @brief Type of a structure representing an SDC driver.
*/
typedef struct SDCDriver SDCDriver;
/**
* @brief Driver configuration structure.
* @note It could be empty on some architectures.
*/
typedef struct {
uint32_t dummy;
} SDCConfig;
/**
* @brief @p SDCDriver specific methods.
*/
#define _sdc_driver_methods \
_mmcsd_block_device_methods
/**
* @extends MMCSDBlockDeviceVMT
*
* @brief @p SDCDriver virtual methods table.
*/
struct SDCDriverVMT {
_sdc_driver_methods
};
/**
* @brief Structure representing an SDC driver.
*/
struct SDCDriver {
/**
* @brief Virtual Methods Table.
*/
const struct SDCDriverVMT *vmt;
_mmcsd_block_device_data
/**
* @brief Current configuration data.
*/
const SDCConfig *config;
/**
* @brief Various flags regarding the mounted card.
*/
sdcmode_t cardmode;
/**
* @brief Errors flags.
*/
sdcflags_t errors;
/**
* @brief Card RCA.
*/
uint32_t rca;
/* End of the mandatory fields.*/
/**
* @brief Pointer to the non-peripheral SDIO resources.
*/
const sdio_resources_t * resources;
/**
* @brief Thread waiting for I/O completion IRQ.
*/
Thread *thread;
};
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @name R1 response utilities
* @{
*/
/**
* @brief Evaluates to @p TRUE if the R1 response contains error flags.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_ERROR(r1) (((r1) & MMCSD_R1_ERROR_MASK) != 0)
/**
* @brief Returns the status field of an R1 response.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_STS(r1) (((r1) >> 9) & 15)
/**
* @brief Evaluates to @p TRUE if the R1 response indicates a locked card.
*
* @param[in] r1 the r1 response
*/
#define MMCSD_R1_IS_CARD_LOCKED(r1) (((r1) >> 21) & 1)
/** @} */
#define LPC_SDC_SDIO_MAX_DESCRIPTOR_BYTES 0x1000
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SDC_USE_SDC1 && !defined(__DOXYGEN__)
extern SDCDriver SDCD1;
#endif
#ifdef __cplusplus
extern "C" {
#endif
void sdc_lld_init(void);
void sdc_lld_start(SDCDriver *sdcp);
void sdc_lld_stop(SDCDriver *sdcp);
void sdc_lld_start_clk(SDCDriver *sdcp);
void sdc_lld_set_data_clk(SDCDriver *sdcp);
void sdc_lld_stop_clk(SDCDriver *sdcp);
void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode);
void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg);
bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
uint32_t *resp);
bool_t sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
uint32_t *resp);
bool_t sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
uint32_t *resp);
bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
uint8_t *buf, uint32_t n);
bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
const uint8_t *buf, uint32_t n);
bool_t sdc_lld_sync(SDCDriver *sdcp);
bool_t sdc_lld_is_card_inserted(SDCDriver *sdcp);
bool_t sdc_lld_is_write_protected(SDCDriver *sdcp);
#ifdef __cplusplus
}
#endif
#endif /* HAL_USE_SDC */
#endif /* _SDC_LLD_H_ */
/** @} */

View File

@ -0,0 +1,452 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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_USART0 || defined(__DOXYGEN__)
/** @brief USART0 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_USART2 || defined(__DOXYGEN__)
/** @brief USART2 serial driver identifier.*/
SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_USART3 || defined(__DOXYGEN__)
/** @brief USART3 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
};
#if LPC_SERIAL_USE_USART0
static const uart_resources_t usart0_resources = {
.base = { .clk = &LPC_CGU->BASE_UART0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 4) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART0_CFG, .stat = &LPC_CCU1->CLK_M4_USART0_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_USART0_CFG, .stat = &LPC_CCU2->CLK_APB0_USART0_STAT },
.reset = { .output_index = 44 },
.interrupt = { .irq = USART0_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART0_IRQ_PRIORITY) },
};
#endif
#if LPC_SERIAL_USE_UART1
static const uart_resources_t uart1_resources = {
.base = { .clk = &LPC_CGU->BASE_UART1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 3) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_UART1_CFG, .stat = &LPC_CCU1->CLK_M4_UART1_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_UART1_CFG, .stat = &LPC_CCU2->CLK_APB0_UART1_STAT },
.reset = { .output_index = 45 },
.interrupt = { .irq = UART1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_UART1_IRQ_PRIORITY) },
};
#endif
#if LPC_SERIAL_USE_USART2
static const uart_resources_t usart2_resources = {
.base = { .clk = &LPC_CGU->BASE_UART2_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 2) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART2_CFG, .stat = &LPC_CCU1->CLK_M4_USART2_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_USART2_CFG, .stat = &LPC_CCU2->CLK_APB2_USART2_STAT },
.reset = { .output_index = 46 },
#if defined(LPC43XX_M4)
.interrupt = { .irq = USART2_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY) },
#endif
#if defined(LPC43XX_M0)
.interrupt = { .irq = USART2_OR_C_CAN1_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART2_IRQ_PRIORITY) },
#endif
};
#endif
#if LPC_SERIAL_USE_USART3
static const uart_resources_t usart3_resources = {
.base = { .clk = &LPC_CGU->BASE_UART3_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1 << 1) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_USART3_CFG, .stat = &LPC_CCU1->CLK_M4_USART3_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_USART3_CFG, .stat = &LPC_CCU2->CLK_APB2_USART3_STAT },
.reset = { .output_index = 47 },
.interrupt = { .irq = USART3_IRQn, .priority_mask = CORTEX_PRIORITY_MASK(LPC_SERIAL_USART3_IRQ_PRIORITY) },
};
#endif
/*===========================================================================*/
/* 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_USART_Type *u = sdp->uart;
u->LCR = config->sc_lcr | LCR_DLAB;
u->DLL = config->sc_div;
u->DLM = config->sc_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_USART_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_USART_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_USART_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_USART0 || 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_USART2 || defined(__DOXYGEN__)
static void notify3(GenericQueue *qp) {
(void)qp;
preload(&SD3);
}
#endif
/**
* @brief Driver SD4 output notification.
*/
#if LPC_SERIAL_USE_USART3 || defined(__DOXYGEN__)
static void notify4(GenericQueue *qp) {
(void)qp;
preload(&SD4);
}
#endif
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/**
* @brief USART0 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_USART0 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(USART0_IRQHandler) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD1);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief UART0 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_UART1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(UART1_IRQHandler) {
CH_IRQ_PROLOGUE();
serve_interrupt(&SD2);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief USART2 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_USART2 || defined(__DOXYGEN__)
#if defined(LPC43XX_M4)
CH_IRQ_HANDLER(USART2_IRQHandler)
#endif
#if defined(LPC43XX_M0)
CH_IRQ_HANDLER(USART2_Or_C_CAN1_IRQHandler)
#endif
{
CH_IRQ_PROLOGUE();
serve_interrupt(&SD3);
CH_IRQ_EPILOGUE();
}
#endif
/**
* @brief USART3 IRQ handler.
*
* @isr
*/
#if LPC_SERIAL_USE_USART3 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(USART3_IRQHandler) {
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_USART0
sdObjectInit(&SD1, NULL, notify1);
SD1.uart = LPC_USART0;
SD1.resources = &usart0_resources;
#endif
#if LPC_SERIAL_USE_UART1
sdObjectInit(&SD2, NULL, notify2);
SD2.uart = (LPC_USART_Type *) LPC_UART1;
SD2.resources = &uart1_resources;
#endif
#if LPC_SERIAL_USE_USART2
sdObjectInit(&SD3, NULL, notify3);
SD3.uart = LPC_USART2;
SD3.resources = &usart2_resources;
#endif
#if LPC_SERIAL_USE_USART3
sdObjectInit(&SD4, NULL, notify4);
SD4.uart = LPC_USART3;
SD4.resources = &usart3_resources;
#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) {
base_clock_enable(&sdp->resources->base);
branch_clock_enable(&sdp->resources->branch_register_if);
branch_clock_enable(&sdp->resources->branch_peripheral);
peripheral_reset(&sdp->resources->reset);
interrupt_enable(&sdp->resources->interrupt);
}
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);
interrupt_disable(&sdp->resources->interrupt);
peripheral_reset(&sdp->resources->reset);
branch_clock_disable(&sdp->resources->branch_peripheral);
branch_clock_disable(&sdp->resources->branch_register_if);
base_clock_disable(&sdp->resources->base);
}
}
#endif /* HAL_USE_SERIAL */
/** @} */

View File

@ -0,0 +1,342 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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 IER_MS 8
#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_DMAMODE 8
#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 LSR_TXERR 0x100 /* Smart Card T=0 mode only. */
#define TER_ENABLE 0x01
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
* @brief USART0 driver enable switch.
* @details If set to @p TRUE the support for USART0 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_USART0) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_USART0 FALSE
#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 FALSE
#endif
/**
* @brief USART2 driver enable switch.
* @details If set to @p TRUE the support for USART2 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_USART2) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_USART2 FALSE
#endif
/**
* @brief USART3 driver enable switch.
* @details If set to @p TRUE the support for USART3 is included.
* @note The default is @p TRUE .
*/
#if !defined(LPC_SERIAL_USE_USART3) || defined(__DOXYGEN__)
#define LPC_SERIAL_USE_USART3 FALSE
#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 USART0 PCLK divider.
*/
#if !defined(LPC_SERIAL_USART0CLKDIV) || defined(__DOXYGEN__)
#define LPC_SERIAL_USART0CLKDIV 1
#endif
/**
* @brief UART1 PCLK divider.
*/
#if !defined(LPC_SERIAL_UART1CLKDIV) || defined(__DOXYGEN__)
#define LPC_SERIAL_UART1CLKDIV 1
#endif
/**
* @brief USART2 PCLK divider.
*/
#if !defined(LPC_SERIAL_USART2CLKDIV) || defined(__DOXYGEN__)
#define LPC_SERIAL_USART2CLKDIV 1
#endif
/**
* @brief USART3 PCLK divider.
*/
#if !defined(LPC_SERIAL_USART3CLKDIV) || defined(__DOXYGEN__)
#define LPC_SERIAL_USART3CLKDIV 1
#endif
/**
* @brief USART0 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_USART0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#if defined(LPC43XX_M4)
#define LPC_SERIAL_USART0_IRQ_PRIORITY 3
#else
#define LPC_SERIAL_USART0_IRQ_PRIORITY 7
#endif
#endif
/**
* @brief UART1 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_UART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#if defined(LPC43XX_M4)
#define LPC_SERIAL_UART1_IRQ_PRIORITY 3
#else
#define LPC_SERIAL_UART1_IRQ_PRIORITY 7
#endif
#endif
/**
* @brief USART2 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#if defined(LPC43XX_M4)
#define LPC_SERIAL_USART2_IRQ_PRIORITY 3
#else
#define LPC_SERIAL_USART2_IRQ_PRIORITY 7
#endif
#endif
/**
* @brief USART3 interrupt priority level setting.
*/
#if !defined(LPC_SERIAL_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#if defined(LPC43XX_M4)
#define LPC_SERIAL_USART3_IRQ_PRIORITY 3
#else
#define LPC_SERIAL_USART3_IRQ_PRIORITY 7
#endif
#endif
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#if (LPC_SERIAL_USART0CLKDIV < 1) || (LPC_SERIAL_USART0CLKDIV > 255)
#error "invalid LPC_SERIAL_USART0CLKDIV setting"
#endif
#if (LPC_SERIAL_UART1CLKDIV < 1) || (LPC_SERIAL_UART1CLKDIV > 255)
#error "invalid LPC_SERIAL_UART1CLKDIV setting"
#endif
#if (LPC_SERIAL_USART2CLKDIV < 1) || (LPC_SERIAL_USART2CLKDIV > 255)
#error "invalid LPC_SERIAL_USART2CLKDIV setting"
#endif
#if (LPC_SERIAL_USART3CLKDIV < 1) || (LPC_SERIAL_USART3CLKDIV > 255)
#error "invalid LPC_SERIAL_USART3CLKDIV setting"
#endif
#if (LPC_SERIAL_FIFO_PRELOAD < 1) || (LPC_SERIAL_FIFO_PRELOAD > 16)
#error "invalid LPC_SERIAL_FIFO_PRELOAD setting"
#endif
/**
* @brief USART0 clock.
*/
#define LPC_SERIAL_USART0_PCLK \
(LPC_MAINCLK / LPC_SERIAL_USART0CLKDIV)
/**
* @brief UART1 clock.
*/
#define LPC_SERIAL_UART1_PCLK \
(LPC_MAINCLK / LPC_SERIAL_UART1CLKDIV)
/**
* @brief USART2 clock.
*/
#define LPC_SERIAL_USART2_PCLK \
(LPC_MAINCLK / LPC_SERIAL_USART2CLKDIV)
/**
* @brief USART3 clock.
*/
#define LPC_SERIAL_USART3_PCLK \
(LPC_MAINCLK / LPC_SERIAL_USART3CLKDIV)
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Structure used for UART configuration.
*/
/**
* @brief LPC 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 Divisor value.
*/
uint32_t sc_div;
/**
* @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 UART registers block.*/ \
LPC_USART_Type *uart; \
/* Pointer to the non-peripheral SSP resources.*/ \
const uart_resources_t * resources;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#if LPC_SERIAL_USE_USART0 && !defined(__DOXYGEN__)
extern SerialDriver SD1;
#endif
#if LPC_SERIAL_USE_UART1 && !defined(__DOXYGEN__)
extern SerialDriver SD2;
#endif
#if LPC_SERIAL_USE_USART2 && !defined(__DOXYGEN__)
extern SerialDriver SD3;
#endif
#if LPC_SERIAL_USE_USART3 && !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,466 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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__)
/* LPC43xx SSP appears to be ARM PrimeCell Synchronous Serial Port. */
/*===========================================================================*/
/* 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. */
/*===========================================================================*/
#if LPC_SPI_USE_SSP0
static const ssp_resources_t ssp0_resources = {
.base = { .clk = &LPC_CGU->BASE_SSP0_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1U << 6) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_SSP0_CFG, .stat = &LPC_CCU1->CLK_M4_SSP0_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB0_SSP0_CFG, .stat = &LPC_CCU2->CLK_APB0_SSP0_STAT },
.reset = { .output_index = 50 },
};
#endif /* LPC_SPI_USE_SSP0 */
#if LPC_SPI_USE_SSP1
static const ssp_resources_t ssp1_resources = {
.base = { .clk = &LPC_CGU->BASE_SSP1_CLK, .stat = &LPC_CCU2->BASE_STAT, .stat_mask = (1U << 5) },
.branch_register_if = { .cfg = &LPC_CCU1->CLK_M4_SSP1_CFG, .stat = &LPC_CCU1->CLK_M4_SSP1_STAT },
.branch_peripheral = { .cfg = &LPC_CCU2->CLK_APB2_SSP1_CFG, .stat = &LPC_CCU2->CLK_APB2_SSP1_STAT },
.reset = { .output_index = 51 },
};
#endif /* LPC_SPI_USE_SSP1 */
/*===========================================================================*/
/* 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_SSPx_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_SSPx_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 defined(LPC43XX_M4)
#if LPC_SPI_USE_SSP0 || defined(__DOXYGEN__)
/**
* @brief SSP0 interrupt handler.
*
* @isr
*/
CH_IRQ_HANDLER(SSP0_IRQHandler) {
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(SSP1_IRQHandler) {
CH_IRQ_PROLOGUE();
spi_serve_interrupt(&SPID2);
CH_IRQ_EPILOGUE();
}
#endif
#endif
#if defined(LPC43XX_M0)
#if LPC_SPI_USE_SSP0 || LPC_SPI_USE_SSP1 || defined(__DOXYGEN__)
CH_IRQ_HANDLER(SSP0_Or_SSP1_IRQHandler) {
CH_IRQ_PROLOGUE();
#if LPC_SPI_USE_SSP0
if( LPC_SSP0->MIS ) spi_serve_interrupt(&SPID1);
#endif
#if LPC_SPI_USE_SSP1
if( LPC_SSP1->MIS ) spi_serve_interrupt(&SPID2);
#endif
CH_IRQ_EPILOGUE();
}
#endif
#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;
SPID1.resources = &ssp0_resources;
#endif /* LPC_SPI_USE_SSP0 */
#if LPC_SPI_USE_SSP1
spiObjectInit(&SPID2);
SPID2.ssp = LPC_SSP1;
SPID2.resources = &ssp1_resources;
#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) {
base_clock_enable(&spip->resources->base);
branch_clock_enable(&spip->resources->branch_register_if);
branch_clock_enable(&spip->resources->branch_peripheral);
peripheral_reset(&spip->resources->reset);
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
#if defined(LPC43XX_M4)
nvicEnableVector(SSP0_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_IRQ_PRIORITY));
#endif
#if defined(LPC43XX_M0)
nvicEnableVector(SSP0_OR_SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_OR_SSP1_IRQ_PRIORITY));
#endif
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
#if defined(LPC43XX_M4)
nvicEnableVector(SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP1_IRQ_PRIORITY));
#endif
#if defined(LPC43XX_M0)
nvicEnableVector(SSP0_OR_SSP1_IRQn,
CORTEX_PRIORITY_MASK(LPC_SPI_SSP0_OR_SSP1_IRQ_PRIORITY));
#endif
}
#endif
}
/* Configuration.*/
spip->ssp->IMSC = 0;
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;
spip->ssp->IMSC = 0;
#if LPC_SPI_USE_SSP0
if (&SPID1 == spip) {
#if defined(LPC43XX_M4)
nvicDisableVector(SSP0_IRQn);
#endif
#if defined(LPC43XX_M0)
#if LPC_SPI_USE_SSP1
/* Disable only if other SSP is stopped. */
/* TODO: Won't work correctly if SSPs are split between cores! */
if(SPID2.state == SPI_STOP) {
#endif
nvicDisableVector(SSP0_OR_SSP1_IRQn);
#if LPC_SPI_USE_SSP1
}
#endif
#endif
}
#endif
#if LPC_SPI_USE_SSP1
if (&SPID2 == spip) {
#if defined(LPC43XX_M4)
nvicDisableVector(SSP1_IRQn);
#endif
#if defined(LPC43XX_M0)
#if LPC_SPI_USE_SSP0
/* Disable only if other SSP is stopped. */
/* TODO: Won't work correctly if SSPs are split between cores! */
if(SPID1.state == SPI_STOP) {
#endif
nvicDisableVector(SSP0_OR_SSP1_IRQn);
#if LPC_SPI_USE_SSP1
}
#endif
#endif
}
#endif
peripheral_reset(&spip->resources->reset);
branch_clock_disable(&spip->resources->branch_peripheral);
branch_clock_disable(&spip->resources->branch_register_if);
base_clock_disable(&spip->resources->base);
}
}
/**
* @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,359 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
* @note Copied and modified from LPC11Uxx/spi_lld.h
*
* @addtogroup SPI
* @{
*/
#ifndef _SPI_LLD_H_
#define _SPI_LLD_H_
#if HAL_USE_SPI || defined(__DOXYGEN__)
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
// ------------------------------------------------------------------------------------------------
// ----- SSP0/1 -----
// ------------------------------------------------------------------------------------------------
/**
* @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
#if defined(LPC43XX)
#define DMACR_RXDMAE 1
#define DMACR_TXDMAE 2
#endif
/*===========================================================================*/
/* 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 TRUE
#endif
#if !defined(LPC43XX)
/**
* @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
#endif /* !defined(LPC43XX) */
/**
* @brief SPI0 interrupt priority level setting.
*/
#if defined(LPC43XX_M4)
#if !defined(LPC_SPI_SSP0_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0_IRQ_PRIORITY 1
#endif
/**
* @brief SPI1 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP1_IRQ_PRIORITY 1
#endif
#endif
#if defined(LPC43XX_M0)
/**
* @brief SPI0 or SSP1 interrupt priority level setting.
*/
#if !defined(LPC_SPI_SSP0_OR_SSP1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define LPC_SPI_SSP0_OR_SSP1_IRQ_PRIORITY 1
#endif
#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 defined(LPC43XX_M4)
#if LPC_SPI_USE_SSP0 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC_SPI_SSP0_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to SSP0"
#endif
#if LPC_SPI_USE_SSP1 && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC_SPI_SSP1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to SSP1"
#endif
#endif
#if defined(LPC43XX_M0)
#if (LPC_SPI_USE_SSP0 || LPC_SPI_USE_SSP1) && \
!CORTEX_IS_VALID_KERNEL_PRIORITY(LPC_SPI_SSP0_OR_SSP1_IRQ_PRIORITY)
#error "Invalid IRQ priority assigned to SSP0/SSP1"
#endif
#endif
#if !defined(LPC43XX) && ((LPC_SPI_SSP0CLKDIV < 1) || (LPC_SPI_SSP0CLKDIV > 255))
#error "invalid LPC_SPI_SSP0CLKDIV setting"
#endif
#if !defined(LPC43XX) && ((LPC_SPI_SSP1CLKDIV < 1) || (LPC_SPI_SSP1CLKDIV > 255))
#error "invalid LPC_SPI_SSP1CLKDIV setting"
#endif
#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 \
(LPC43XX_MAINCLK / LPC_SPI_SSP0CLKDIV)
/**
* @brief SSP1 clock.
*/
#define LPC_SPI_SSP1_PCLK \
(LPC43XX_MAINCLK / LPC_SPI_SSP1CLKDIV)
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type of a structure representing an SPI driver.
*/
typedef struct SPIDriver SPIDriver;
/**
* @brief SPI notification callback type.
*
* @param[in] spip pointer to the @p SPIDriver object triggering the
* callback
*/
typedef void (*spicallback_t)(SPIDriver *spip);
/**
* @brief Driver configuration structure.
*/
typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
iopadid_t sspad;
/**
* @brief SSP CR0 initialization data.
*/
uint16_t cr0;
/**
* @brief SSP CPSR initialization data.
*/
uint32_t cpsr;
} SPIConfig;
/**
* @brief Structure representing an 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_SSPx_Type *ssp;
/**
* @brief Pointer to the non-peripheral SSP resources.
*/
const ssp_resources_t * resources;
/**
* @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,151 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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_M0/hal_lld.c
* @brief LPC43xx M0 HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/* TODO: Somehow share this value between the M4 and M0 cores. The M0 always
* runs at the same speed as the M4 core.
*/
static halclock_t hal_clock_f = LPC43XX_M0_CLK_PLL1_AT_BOOT;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
halclock_t halLPCGetSystemClock(void) {
return hal_clock_f;
}
void halLPCSetSystemClock(const halclock_t new_frequency) {
hal_clock_f = new_frequency;
}
/* TODO: Expose RIT code, move elsewhere. */
static void ritimer_stop(void) {
LPC_RITIMER->CTRL =
(0 << 0) /* RITINT */
| (1 << 1) /* RITENCLR */
| (1 << 2) /* RITENBR */
| (0 << 3) /* RITEN */
;
}
static void ritimer_start(void) {
LPC_RITIMER->CTRL =
(0 << 0) /* RITINT */
| (1 << 1) /* RITENCLR */
| (1 << 2) /* RITENBR */
| (1 << 3) /* RITEN */
;
}
void systick_adjust_period(const uint32_t counts_per_tick) {
ritimer_stop();
LPC_RITIMER->COMPVAL = counts_per_tick;
LPC_RITIMER->COUNTER = 0;
ritimer_start();
}
void systick_stop() {
ritimer_stop();
}
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
/* Initialize timer 3 to serve as a cycle (PCLK) counter. */
LPC_CCU1->CLK_M4_TIMER3_CFG.AUTO = 1;
LPC_CCU1->CLK_M4_TIMER3_CFG.RUN = 1;
while(!LPC_CCU1->CLK_M4_TIMER3_STAT.RUN);
LPC_TIMER3->TCR = (1 << 1); /* CRST=1 */
LPC_TIMER3->TCR = 0; /* CRST=0 */
LPC_TIMER3->TC = 0;
LPC_TIMER3->PR = 0;
LPC_TIMER3->TCR = (1 << 0); /* CEN=1 */
/* Initialize repetitive interrupt timer (RIT) to act like SysTick for
* operating system process timing.
*/
LPC_CCU1->CLK_M4_RITIMER_CFG.AUTO = 1;
LPC_CCU1->CLK_M4_RITIMER_CFG.RUN = 1;
while(!LPC_CCU1->CLK_M4_RITIMER_STAT.RUN);
LPC_RITIMER->CTRL =
(1 << 0) /* RITINT */
| (1 << 1) /* RITENCLR */
| (1 << 2) /* RITENBR */
| (0 << 3) /* RITEN */
;
LPC_RITIMER->MASK = 0;
systick_adjust_period(LPC43XX_M0_CLK_PLL1_AT_BOOT / CH_FREQUENCY - 1);
nvicEnableVector(RITIMER_OR_WWDT_IRQn, CORTEX_PRIORITY_MASK(CORTEX_PRIORITY_SYSTICK));
}
/* Work-around to use RITimer in place of SysTick, which isn't available on
* the LPC43xx M0 core.
*/
CH_IRQ_HANDLER(RITimer_Or_WWDT_IRQHandler) {
/* Same code as in SysTickVector */
CH_IRQ_PROLOGUE();
chSysLockFromIsr();
chSysTimerHandlerI();
chSysUnlockFromIsr();
LPC_RITIMER->CTRL =
(1 << 0) /* RITINT */
| (1 << 1) /* RITENCLR */
| (1 << 2) /* RITENBR */
| (1 << 3) /* RITEN */
;
CH_IRQ_EPILOGUE();
}
/** @} */

View File

@ -0,0 +1,158 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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_M0/hal_lld.h
* @brief HAL subsystem low level driver header template.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "lpc43xx_m0.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Defines the support for realtime counters in the HAL.
*/
#define HAL_IMPLEMENTS_COUNTERS TRUE
/**
* @brief Platform name.
*/
#define PLATFORM_NAME "LPC43xx M0"
/*===========================================================================*/
/* Platform capabilities. */
/*===========================================================================*/
/*===========================================================================*/
/* Platform specific friendly IRQ names. */
/*===========================================================================*/
/**
* @name IRQ VECTOR names
* @{
*/
#define RTC_IRQHandler Vector40 /**< RTC */
#define M4Core_IRQHandler Vector44 /**< Cortex-M4 */
#define DMA_IRQHandler Vector48 /**< DMA */
#define Ethernet_IRQHandler Vector54 /**< Ethernet */
#define SDIO_IRQHandler Vector58 /**< SD/MMC */
#define LCD_IRQHandler Vector5C /**< LCD */
#define USB0_IRQHandler Vector60 /**< USB0: OTG */
#define USB1_IRQHandler Vector64 /**< USB1 */
#define SCT_IRQHandler Vector68 /**< SCT combined */
#define RITimer_Or_WWDT_IRQHandler Vector6C /**< RI Timer or WWDT */
#define Timer0_IRQHandler Vector70 /**< Timer 0 */
#define GINT1_IRQHandler Vector74 /**< GPIO global interrupt 1 */
#define PIN_INT4_IRQHandler Vector78 /**< GPIO pin interrupt 4 */
#define Timer3_IRQHandler Vector7C /**< Timer 3 */
#define MCPWM_IRQHandler Vector80 /**< Motor control PWM */
#define ADC0_IRQHandler Vector84 /**< ADC0 */
#define I2C0_Or_I2C1_IRQHandler Vector88 /**< I2C0 or I2C1 */
#define SGPIO_IRQHandler Vector8C /**< SGPIO */
#define SPI_Or_DAC_IRQHandler Vector90 /**< SPI or DAC */
#define ADC1_IRQHandler Vector94 /**< ADC1 */
#define SSP0_Or_SSP1_IRQHandler Vector98 /**< SSP0 or SSP1 */
#define EventRouter_IRQHandler Vector9C /**< Event router */
#define USART0_IRQHandler VectorA0 /**< USART0 */
#define UART1_IRQHandler VectorA4 /**< UART1 */
#define USART2_Or_C_CAN1_IRQHandler VectorA8 /**< USART2 or C_CAN1 */
#define USART3_IRQHandler VectorAC /**< USART3 */
#define I2S0_Or_I2S1_QEI_IRQHandler VectorB0 /**< I2S0 or I2S1 or QEI */
#define C_CAN0_IRQHandler VectorB4 /**< C_CAN0 */
#define SPIFI_Or_ADCHS_IRQHandler VectorB8 /**< SPIFI or ADCHS */
#define M0SUB_IRQHandler VectorBC /**< M0SUB */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#define LPC43XX_M0_CLK_PLL1_AT_BOOT 96000000
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing a system clock frequency.
*/
typedef uint32_t halclock_t;
/**
* @brief Type of the realtime free counter value.
*/
typedef uint32_t halrtcnt_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the current value of the system free running counter.
* @note This service is implemented by returning the content of timer 3's
* TC (counter value) register.
*
* @return The value of the system free running counter of
* type halrtcnt_t.
*
* @notapi
*/
#define hal_lld_get_counter_value() (LPC_TIMER3->TC)
/**
* @brief Realtime counter frequency.
* @note The DWT_CYCCNT register is incremented directly by the system
* clock so this function returns STM32_HCLK.
*
* @return The realtime counter frequency of type halclock_t.
*
* @notapi
*/
#define hal_lld_get_counter_frequency() halLPCGetSystemClock()
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void hal_lld_init(void);
void systick_stop(void);
void systick_adjust_period(const uint32_t counts_per_tick);
halclock_t halLPCGetSystemClock(void);
void halLPCSetSystemClock(const halclock_t new_frequency);
#ifdef __cplusplus
}
#endif
#endif /* _HAL_LLD_H_ */
/** @} */

View File

@ -0,0 +1,114 @@
/*
ChibiOS/RT - Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup lpc43xx_m0
* @{
*/
#ifndef __LPC43XX_M0_H
#define __LPC43XX_M0_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Configuration_section_for_CMSIS
* @{
*/
/**
* @brief Configuration of the Cortex-M0 Processor and Core Peripherals
*/
#define __CM0_REV 0 /*!< Core revision r0p0 */
#define __MPU_PRESENT 0 /*!< LPC43XX M0 does not provide MPU */
#define __NVIC_PRIO_BITS 2 /*!< LPC43XX M0 uses 2 Bits for the Priority Levels */
#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */
/**
* @brief LPC43XX M0 Interrupt Number Definition, according to the selected device
* in @ref Library_configuration_section
*/
typedef enum IRQn {
/****** Cortex-M0 Processor Exceptions Numbers ****************************************************************/
Reset_IRQn = -15, /*!< 1 Reset Vector, invoked on Power up and warm reset */
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
HardFault_IRQn = -13, /*!< 3 Cortex-M0 Hard Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M0 SV Call Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M0 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M0 System Tick Interrupt */
/****** LPC43xx M0 specific Interrupt Numbers *****************************************************************/
RTC_IRQn = 0, /*!< 16 RTC */
M4CORE_IRQn = 1, /*!< 17 Cortex-M4; Latched TXEV; for M0APP-M4 communication */
DMA_IRQn = 2, /*!< 18 DMA */
/* 3: 19 Reserved */
/* 4: 20 ORed flash bank A, flash bank B, EEPROM interrupts */
ETHERNET_IRQn = 5, /*!< 21 Ethernet */
SDIO_IRQn = 6, /*!< 22 SD/MMC */
LCD_IRQn = 7, /*!< 23 LCD */
USB0_IRQn = 8, /*!< 24 OTG interrupt */
USB1_IRQn = 9, /*!< 25 USB1 */
SCT_IRQn = 10, /*!< 26 SCT combined interrupt */
RITIMER_OR_WWDT_IRQn = 11, /*!< 27 RITIMER or WWDT */
TIMER0_IRQn = 12, /*!< 28 TIMER0 */
GINT1_IRQn = 13, /*!< 29 GPIO globak interrupt 1 */
PIN_INT4_IRQn = 14, /*!< 30 GPIO pin interrupt 4 */
TIMER3_IRQn = 15, /*!< 31 TIMER3 */
MCPWM_IRQn = 16, /*!< 32 Motor control PWM */
ADC0_IRQn = 17, /*!< 33 ADC0 */
I2C0_OR_I2C1_IRQn = 18, /*!< 34 I2C0 or I2C1 */
SGPIO_IRQn = 19, /*!< 35 SGPIO */
SPI_OR_DAC_IRQn = 20, /*!< 36 SPI interrupt ORed with DAC interrupt */
ADC1_IRQn = 21, /*!< 37 ADC1 */
SSP0_OR_SSP1_IRQn = 22, /*!< 38 SSP0 interrupt ORed with SSP1 interrupt */
EVENTROUTER_IRQn = 23, /*!< 39 Event router */
USART0_IRQn = 24, /*!< 40 USART0 */
UART1_IRQn = 25, /*!< 41 Combined UART interrupt with Modem interrupt */
USART2_OR_C_CAN1_IRQn = 26, /*!< 42 USART2 interrupt ORed with C_CAN1 interrupt */
USART3_IRQn = 27, /*!< 43 Combined USART interrupt with IrDA interrupt */
I2S0_OR_I2S1_QEI_IRQn = 28, /*!< 44 I2S0 OR I2S1 OR QEI interrupt */
C_CAN0_IRQn = 29, /*!< 45 C_CAN0 */
SPIFI_OR_ADCHS_IRQn = 30, /*!< 46 SPIFI OR ADCHS interrupt */
M0SUB_IRQn = 31, /*!< 47 M0SUB core */
TIMER1_IRQn = 32
} IRQn_Type;
/**
* @}
*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "core_cm0.h" /* Cortex-M0 processor and core peripherals */
#include "lpc43xx.inc"
#include "lpc43xx.h"
#endif /* __LPC43XX_M0_H */
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,18 @@
# List of all the LPC43xx M0 platform files.
set(PLATFORMSRC
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0/hal_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/gpt_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/i2c_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/pal_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
)
# Required include directories
set(PLATFORMINC
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx
)

View File

@ -0,0 +1,14 @@
# List of all the LPC43xx M0 platform files.
PLATFORMSRC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0/hal_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/gpt_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/i2c_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/pal_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
# Required include directories
PLATFORMINC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M0 \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx

View File

@ -0,0 +1,97 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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_M4/hal_lld.c
* @brief LPC43xx M4 HAL subsystem low level driver source.
*
* @addtogroup HAL
* @{
*/
#include "ch.h"
#include "hal.h"
/*===========================================================================*/
/* Driver local definitions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver local variables and types. */
/*===========================================================================*/
/* TODO: Somehow share this value between the M4 and M0 cores. The M0 always
* runs at the same speed as the M4 core.
*/
static halclock_t hal_clock_f = LPC43XX_M4_CLK;
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
halclock_t halLPCGetSystemClock(void) {
return hal_clock_f;
}
void halLPCSetSystemClock(const halclock_t new_frequency) {
hal_clock_f = new_frequency;
}
void systick_stop() {
SysTick->CTRL &= ~(SysTick_CTRL_ENABLE_Msk | SysTick_CTRL_TICKINT_Msk);
}
void systick_adjust_period(const uint32_t counts_per_tick) {
SysTick->LOAD = counts_per_tick;
}
/**
* @brief Low level HAL driver initialization.
*
* @notapi
*/
void hal_lld_init(void) {
#if defined(LPC43XX_M4_CLK_SRC)
LPC_CGU->BASE_M4_CLK.AUTOBLOCK = 1;
LPC_CGU->BASE_M4_CLK.CLK_SEL = LPC43XX_M4_CLK_SRC;
#endif
/* SysTick initialization using the system clock.*/
systick_adjust_period(halLPCGetSystemClock() / 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;
}
/** @} */

View File

@ -0,0 +1,177 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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_M4/hal_lld.h
* @brief HAL subsystem low level driver header.
*
* @addtogroup HAL
* @{
*/
#ifndef _HAL_LLD_H_
#define _HAL_LLD_H_
#include "lpc43xx_m4.h"
/*===========================================================================*/
/* Driver constants. */
/*===========================================================================*/
/**
* @brief Defines the support for realtime counters in the HAL.
*/
#define HAL_IMPLEMENTS_COUNTERS TRUE
/**
* @name Platform identification
* @{
*/
#define PLATFORM_NAME "LPC43xx M4"
/** @} */
/*===========================================================================*/
/* Platform capabilities. */
/*===========================================================================*/
/*===========================================================================*/
/* Platform specific friendly IRQ names. */
/*===========================================================================*/
/**
* @name IRQ VECTOR names
* @{
*/
#define DAC_IRQHandler Vector40 /**< DAC */
#define MAPP_IRQHandler Vector44 /**< Cortex-M0APP */
#define DMA_IRQHandler Vector48 /**< DMA */
#define Ethernet_IRQHandler Vector54 /**< Ethernet */
#define SDIO_IRQHandler Vector58 /**< SD/MMC */
#define LCD_IRQHandler Vector5C /**< LCD */
#define USB0_IRQHandler Vector60 /**< USB0: OTG */
#define USB1_IRQHandler Vector64 /**< USB1 */
#define SCT_IRQHandler Vector68 /**< SCT combined */
#define RITimer_IRQHandler Vector6C /**< RI Timer */
#define Timer0_IRQHandler Vector70 /**< Timer 0 */
#define Timer1_IRQHandler Vector74 /**< Timer 1 */
#define Timer2_IRQHandler Vector78 /**< Timer 2 */
#define Timer3_IRQHandler Vector7C /**< Timer 3 */
#define MCPWM_IRQHandler Vector80 /**< Motor control PWM */
#define ADC0_IRQHandler Vector84 /**< ADC0 */
#define I2C0_IRQHandler Vector88 /**< I2C0 */
#define I2C1_IRQHandler Vector8C /**< I2C1 */
#define SPI_IRQHandler Vector90 /**< SPI */
#define ADC1_IRQHandler Vector94 /**< ADC1 */
#define SSP0_IRQHandler Vector98 /**< SSP0 */
#define SSP1_IRQHandler Vector9C /**< SSP1 */
#define USART0_IRQHandler VectorA0 /**< USART0 */
#define UART1_IRQHandler VectorA4 /**< UART1 */
#define USART2_IRQHandler VectorA8 /**< USART2 */
#define USART3_IRQHandler VectorAC /**< USART3 */
#define I2S0_IRQHandler VectorB0 /**< I2S0 */
#define I2S1_IRQHandler VectorB4 /**< I2S1 */
#define SPIFI_IRQHandler VectorB8 /**< SPIFI */
#define SGPIO_IRQHandler VectorBC /**< SGPIO */
#define PIN_INT0_IRQHandler VectorC0 /**< GPIO pin interrupt 0 */
#define PIN_INT1_IRQHandler VectorC4 /**< GPIO pin interrupt 1 */
#define PIN_INT2_IRQHandler VectorC8 /**< GPIO pin interrupt 2 */
#define PIN_INT3_IRQHandler VectorCC /**< GPIO pin interrupt 3 */
#define PIN_INT4_IRQHandler VectorD0 /**< GPIO pin interrupt 4 */
#define PIN_INT5_IRQHandler VectorD4 /**< GPIO pin interrupt 5 */
#define PIN_INT6_IRQHandler VectorD8 /**< GPIO pin interrupt 6 */
#define PIN_INT7_IRQHandler VectorDC /**< GPIO pin interrupt 7 */
#define GINT0_IRQHandler VectorE0 /**< GPIO global interrupt 0 */
#define GINT1_IRQHandler VectorE4 /**< GPIO global interrupt 1 */
#define EventRouter_IRQHandler VectorE8 /**< Event router */
#define C_CAN1_IRQHandler VectorEC /**< C_CAN1 */
#define ATimer_IRQHandler VectorF8 /**< Alarm timer */
#define RTC_IRQHandler VectorFC /**< RTC */
#define WWDT_IRQHandler Vector104 /**< WWDT */
#define C_CAN0_IRQHandler Vector10C /**< C_CAN0 */
#define QEI_IRQHandler Vector110 /**< QEI */
/** @} */
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/*===========================================================================*/
/* Derived constants and error checks. */
/*===========================================================================*/
#define LPC43XX_M4_CLK_IRC 12000000
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
* @brief Type representing a system clock frequency.
*/
typedef uint32_t halclock_t;
/**
* @brief Type of the realtime free counter value.
*/
typedef uint32_t halrtcnt_t;
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
/**
* @brief Returns the current value of the system free running counter.
* @note This service is implemented by returning the content of the
* DWT_CYCCNT register.
*
* @return The value of the system free running counter of
* type halrtcnt_t.
*
* @notapi
*/
#define hal_lld_get_counter_value() DWT_CYCCNT
/**
* @brief Realtime counter frequency.
* @note The DWT_CYCCNT register is incremented directly by the system
* clock so this function returns STM32_HCLK.
*
* @return The realtime counter frequency of type halclock_t.
*
* @notapi
*/
#define hal_lld_get_counter_frequency() halLPCGetSystemClock()
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
#ifdef __cplusplus
extern "C" {
#endif
void hal_lld_init(void);
void systick_stop(void);
void systick_adjust_period(const uint32_t counts_per_tick);
halclock_t halLPCGetSystemClock(void);
void halLPCSetSystemClock(const halclock_t new_frequency);
#ifdef __cplusplus
}
#endif
#endif /* _HAL_LLD_H_ */
/** @} */

View File

@ -0,0 +1,277 @@
/*
ChibiOS/RT - Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
*/
/** @addtogroup CMSIS
* @{
*/
/** @addtogroup lpc43xx_m4
* @{
*/
#ifndef __LPC43XX_M4_H
#define __LPC43XX_M4_H
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/** @addtogroup Configuration_section_for_CMSIS
* @{
*/
/**
* @brief Configuration of the Cortex-M4 Processor and Core Peripherals
*/
#define __CM4_REV 0x0001 /*!< Core revision r0p1 */
#define __MPU_PRESENT 1 /*!< LPC43XX M4 provides an MPU */
#define __NVIC_PRIO_BITS 3 /*!< LPC43XX M4 uses 3 Bits for the Priority Levels*/
#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */
#define __FPU_PRESENT 1 /*!< FPU present */
/**
* @brief LPC43XX M4 Interrupt Number Definition, according to the selected device
* in @ref Library_configuration_section
*/
typedef enum IRQn {
/****** Cortex-M4 Processor Exceptions Numbers ****************************************************************/
NonMaskableInt_IRQn = -14, /*!< 2 Non Maskable Interrupt */
MemoryManagement_IRQn = -12, /*!< 4 Cortex-M4 Memory Management Interrupt */
BusFault_IRQn = -11, /*!< 5 Cortex-M4 Bus Fault Interrupt */
UsageFault_IRQn = -10, /*!< 6 Cortex-M4 Usage Fault Interrupt */
SVCall_IRQn = -5, /*!< 11 Cortex-M4 SV Call Interrupt */
DebugMonitor_IRQn = -4, /*!< 12 Cortex-M4 Debug Monitor Interrupt */
PendSV_IRQn = -2, /*!< 14 Cortex-M4 Pend SV Interrupt */
SysTick_IRQn = -1, /*!< 15 Cortex-M4 System Tick Interrupt */
/****** LPC43xx M4 specific Interrupt Numbers *****************************************************************/
DAC_IRQn = 0, /*!< 16 DAC */
M0CORE_IRQn = 1, /*!< 17 Cortex-M0APP; Latched TXEV; for M4-M0APP communication */
DMA_IRQn = 2, /*!< 18 DMA */
/* 3: 19 Reserved */
/* 4: 20 ORed flash bank A, flash bank B, EEPROM interrupts */
ETHERNET_IRQn = 5, /*!< 21 Ethernet */
SDIO_IRQn = 6, /*!< 22 SD/MMC */
LCD_IRQn = 7, /*!< 23 LCD */
USB0_IRQn = 8, /*!< 24 OTG interrupt */
USB1_IRQn = 9, /*!< 25 USB1 */
SCT_IRQn = 10, /*!< 26 SCT combined interrupt */
RITIMER_IRQn = 11, /*!< 27 RITIMER */
TIMER0_IRQn = 12, /*!< 28 TIMER0 */
TIMER1_IRQn = 13, /*!< 29 TIMER1 */
TIMER2_IRQn = 14, /*!< 30 TIMER2 */
TIMER3_IRQn = 15, /*!< 31 TIMER3 */
MCPWM_IRQn = 16, /*!< 32 Motor control PWM */
ADC0_IRQn = 17, /*!< 33 ADC0 */
I2C0_IRQn = 18, /*!< 34 I2C0 */
I2C1_IRQn = 19, /*!< 35 I2C1 */
SPI_IRQn = 20, /*!< 36 SPI */
ADC1_IRQn = 21, /*!< 37 ADC1 */
SSP0_IRQn = 22, /*!< 38 SSP0 */
SSP1_IRQn = 23, /*!< 39 SSP1 */
USART0_IRQn = 24, /*!< 40 USART0 */
UART1_IRQn = 25, /*!< 41 Combined UART interrupt with Modem interrupt */
USART2_IRQn = 26, /*!< 42 USART2 */
USART3_IRQn = 27, /*!< 43 Combined USART interrupt with IrDA interrupt */
I2S0_IRQn = 28, /*!< 44 I2S0 */
I2S1_IRQn = 29, /*!< 45 I2S1 */
SPIFI_IRQn = 30, /*!< 46 SPIFI */
SGPIO_IRQn = 31, /*!< 47 SGPIO */
PIN_INT0_IRQn = 32, /*!< 48 GPIO pin interrupt 0 */
PIN_INT1_IRQn = 33, /*!< 49 GPIO pin interrupt 1 */
PIN_INT2_IRQn = 34, /*!< 50 GPIO pin interrupt 2 */
PIN_INT3_IRQn = 35, /*!< 51 GPIO pin interrupt 3 */
PIN_INT4_IRQn = 36, /*!< 52 GPIO pin interrupt 4 */
PIN_INT5_IRQn = 37, /*!< 53 GPIO pin interrupt 5 */
PIN_INT6_IRQn = 38, /*!< 54 GPIO pin interrupt 6 */
PIN_INT7_IRQn = 39, /*!< 55 GPIO pin interrupt 7 */
GINT0_IRQn = 40, /*!< 56 GPIO global interrupt 0 */
GINT1_IRQn = 41, /*!< 57 GPIO global interrupt 1 */
EVENTROUTER_IRQn = 42, /*!< 58 Event router */
C_CAN_IRQn = 43, /*!< 59 C_CAN1 */
/* 44: 60 Reserved */
/* 45: 61 ADCHS combined */
ATIMER_IRQn = 46, /*!< 62 Alarm timer */
RTC_IRQn = 47, /*!< 63 RTC */
/* 48: 64 Reserved */
WWDT_IRQn = 49, /*!< 65 WWDT */
/* 50: 66 TXEV instruction from the M0 subsystem core */
C_CAN0_IRQn = 51, /*!< 67 C_CAN0 */
QEI_IRQn = 52, /*!< 68 QEI */
} IRQn_Type;
/**
* @}
*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "core_cm4.h" /* Cortex-M4 processor and core peripherals */
#include "lpc43xx.inc"
#include "lpc43xx.h"
#ifdef __cplusplus
/* NOTE: Override old, misbehaving SIMD #defines */
#define __SIMD32_TYPE int32_t
#define __SIMD32(addr) (*(__SIMD32_TYPE **) & (addr))
#define _SIMD32_OFFSET(addr) (*(__SIMD32_TYPE *) (addr))
/* Overload of __SXTB16() to add ROR argument, since using __ROR() as an
* argument to the existing __SXTB16() doesn't produce optimum/sane code.
*/
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SXTB16(uint32_t rm, uint32_t ror)
{
int32_t rd;
__ASM volatile ("sxtb16 %0, %1, ror %2" : "=r" (rd) : "r" (rm), "I" (ror));
return rd;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SXTH(uint32_t rm, uint32_t ror)
{
int32_t rd;
__ASM volatile ("sxth %0, %1, ror %2" : "=r" (rd) : "r" (rm), "I" (ror));
return rd;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMLATB(uint32_t rm, uint32_t rs, uint32_t rn) {
int32_t rd;
__ASM volatile ("smlatb %0, %1, %2, %3" : "=r" (rd) : "r" (rm), "r" (rs), "r" (rn));
return rd;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMLABB(uint32_t rm, uint32_t rs, uint32_t rn) {
int32_t rd;
__ASM volatile("smlabb %0, %1, %2, %3" : "=r" (rd) : "r" (rm), "r" (rs), "r" (rn));
return rd;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SXTAH(uint32_t rn, uint32_t rm, uint32_t ror) {
int32_t rd;
__ASM volatile("sxtah %0, %1, %2, ror %3" : "=r" (rd) : "r" (rn), "r" (rm), "I" (ror));
return rd;
}
/* NOTE: BFI is kinda weird because it modifies RD, copy __SMLALD style? */
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __BFI(uint32_t rd, uint32_t rn, uint32_t lsb, uint32_t width) {
__ASM volatile("bfi %0, %1, %2, %3" : "+r" (rd) : "r" (rn), "I" (lsb), "I" (width));
return rd;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMULBB(uint32_t op1, uint32_t op2) {
int32_t result;
__ASM volatile ("smulbb %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) );
return result;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMULBT(uint32_t op1, uint32_t op2) {
int32_t result;
__ASM volatile ("smulbt %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) );
return result;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMULTB(uint32_t op1, uint32_t op2) {
int32_t result;
__ASM volatile ("smultb %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) );
return result;
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMULTT(uint32_t op1, uint32_t op2) {
int32_t result;
__ASM volatile ("smultt %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) );
return result;
}
#undef __SMULL
__attribute__( ( always_inline ) ) static inline int64_t __SMULL (int32_t op1, int32_t op2)
{
union llreg_u{
uint32_t w32[2];
int64_t w64;
} llr;
__asm volatile ("smull %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2));
return(llr.w64);
}
#undef __SMLALD
__attribute__( ( always_inline ) ) static inline int64_t __SMLALD (uint32_t op1, uint32_t op2, int64_t acc)
{
union llreg_u{
uint32_t w32[2];
int64_t w64;
} llr;
llr.w64 = acc;
__asm volatile ("smlald %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) );
return(llr.w64);
}
#undef __SMLALDX
__attribute__( ( always_inline ) ) static inline int64_t __SMLALDX (uint32_t op1, uint32_t op2, int64_t acc)
{
union llreg_u{
uint32_t w32[2];
int64_t w64;
} llr;
llr.w64 = acc;
__asm volatile ("smlaldx %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) );
return(llr.w64);
}
#undef __SMLSLD
__attribute__( ( always_inline ) ) static inline int64_t __SMLSLD (uint32_t op1, uint32_t op2, int64_t acc)
{
union llreg_u{
uint32_t w32[2];
int64_t w64;
} llr;
llr.w64 = acc;
__asm volatile ("smlsld %0, %1, %2, %3" : "=r" (llr.w32[0]), "=r" (llr.w32[1]): "r" (op1), "r" (op2) , "0" (llr.w32[0]), "1" (llr.w32[1]) );
return(llr.w64);
}
__attribute__( ( always_inline ) ) __STATIC_INLINE int32_t __SMMULR (int32_t op1, int32_t op2)
{
uint32_t result;
__ASM volatile ("smmulr %0, %1, %2" : "=r" (result) : "r" (op1), "r" (op2) );
return(result);
}
#endif /* __cplusplus */
#endif /* __LPC43XX_M4_H */
/**
* @}
*/
/**
* @}
*/

View File

@ -0,0 +1,18 @@
# List of all the LPC43xx M4 platform files.
set(PLATFORMSRC
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4/hal_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/gpt_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/i2c_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/pal_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
)
# Required include directories
set(PLATFORMINC
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx
)

View File

@ -0,0 +1,14 @@
# List of all the LPC43xx M4 platform files.
PLATFORMSRC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4/hal_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/gpt_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/i2c_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/pal_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/rtc_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/sdc_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/serial_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/spi_lld.c \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx/lpc43xx.c
# Required include directories
PLATFORMINC = ${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx_M4 \
${CHIBIOS_PORTAPACK}/os/hal/platforms/LPC43xx

View File

@ -0,0 +1,70 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file GCC/ARMCMx/LPC43xx_M0/cmparams.h
* @brief ARM Cortex-M0 parameters for the LPC43xx.
*
* @defgroup ARMCMx_LPC43xx_M0 LPC43xx Specific Parameters
* @ingroup ARMCMx_SPECIFIC
* @details This file contains the Cortex-M0 specific parameters for the
* LPC43xx platform.
* @{
*/
#ifndef _CMPARAMS_H_
#define _CMPARAMS_H_
/**
* @brief Cortex core model.
*/
#define CORTEX_MODEL CORTEX_M0
/**
* @brief Systick unit presence.
*/
#define CORTEX_HAS_ST FALSE
/**
* @brief Memory Protection unit presence.
*/
#define CORTEX_HAS_MPU FALSE
/**
* @brief Floating Point unit presence.
*/
#define CORTEX_HAS_FPU FALSE
/**
* @brief Number of bits in priority masks.
*/
#define CORTEX_PRIORITY_BITS 2
#endif /* _CMPARAMS_H_ */
/** @} */

View File

@ -0,0 +1,148 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
*/
/*
* LPC43xx M0 memory setup.
*/
__main_stack_size__ = 0x0400; /* Exceptions/interrupts stack */
__process_stack_size__ = 0x1000; /* main() stack */
MEMORY
{
flash (rx) : org = 0x00000000, len = 1024k /* SPIFI flash @ 0x140????? */
ram (rwx) : org = 0x20000000, len = 64k /* AHB SRAM @ 0x20000000 */
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
ENTRY(ResetHandler)
SECTIONS
{
. = 0;
_text = .;
startup : ALIGN(16) SUBALIGN(16)
{
KEEP(*(vectors))
} > flash
constructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__init_array_end = .);
} > flash
destructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__fini_array_start = .);
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
PROVIDE(__fini_array_end = .);
} > flash
.text : ALIGN(16) SUBALIGN(16)
{
*(.text.startup.*)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > flash
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > flash
.eh_frame_hdr :
{
*(.eh_frame_hdr)
} > flash
.eh_frame : ONLY_IF_RO
{
*(.eh_frame)
} > flash
.textalign : ONLY_IF_RO
{
. = ALIGN(8);
} > flash
. = ALIGN(4);
_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__ = .;
} > ram
.data ALIGN(4) : AT (_textdata)
{
. = ALIGN(4);
PROVIDE(_data = .);
*(.data)
*(.data.*)
*(.ramtext)
. = ALIGN(4);
PROVIDE(_edata = .);
} > ram
_textend = LOADADDR(.data) + SIZEOF(.data);
.bss ALIGN(4) : ALIGN(4)
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
PROVIDE(_bss_end = .);
} > ram
}
PROVIDE(end = .);
_end = .;
__heap_base__ = _end;
__heap_end__ = __ram_end__;

View File

@ -0,0 +1,21 @@
# List of the ChibiOS/RT Cortex-M0 LPC43xx port files.
set(PORTSRC
${CHIBIOS}/os/ports/GCC/ARMCMx/crt0.c
${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore.c
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore_v6m.c
${CHIBIOS}/os/ports/common/ARMCMx/nvic.c
)
set(PORTASM)
set(PORTINC
${CHIBIOS}/os/ports/common/ARMCMx/CMSIS/include
${CHIBIOS}/os/ports/common/ARMCMx
${CHIBIOS}/os/ports/GCC/ARMCMx
${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0
)
set(PORTLD
${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0/ld
)

View File

@ -0,0 +1,15 @@
# List of the ChibiOS/RT Cortex-M0 LPC43xx port files.
PORTSRC = $(CHIBIOS)/os/ports/GCC/ARMCMx/crt0.c \
$(CHIBIOS_PORTAPACK)/os/ports/GCC/ARMCMx/LPC43xx_M0/vectors.c \
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore.c \
${CHIBIOS}/os/ports/GCC/ARMCMx/chcore_v6m.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_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0
PORTLD = ${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M0/ld

View File

@ -0,0 +1,206 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file GCC/ARMCMx/LPC43xx_M0/vectors.c
* @brief Interrupt vectors for the LPC43xx M0 family.
*
* @defgroup ARMCMx_LPC43xx_M0_VECTORS LPC43xx Interrupt Vectors
* @ingroup ARMCMx_SPECIFIC
* @details Interrupt vectors for the LPC43xx M0 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[32];
} 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);
#endif
/**
* @brief LPC43xx M0 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
}
};
/**
* @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")));
/** @} */

View File

@ -0,0 +1,70 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
Copyright (C) 2014 Jared Boone, ShareBrained Techology
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file GCC/ARMCMx/LPC43xx_M4/cmparams.h
* @brief ARM Cortex-M4 parameters for the LPC43xx.
*
* @defgroup ARMCMx_LPC43xx_M4 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 3
#endif /* _CMPARAMS_H_ */
/** @} */

View File

@ -0,0 +1,148 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
*/
/*
* LPC43xx M4 memory setup.
*/
__main_stack_size__ = 0x0400; /* Exceptions/interrupts stack */
__process_stack_size__ = 0x1000; /* main() stack */
MEMORY
{
flash (rx) : org = 0x00000000, len = 32752 /* Local SRAM @ 0x10080000 */
ram (rwx) : org = 0x10000000, len = 96k /* Local SRAM @ 0x10000000 */
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
ENTRY(ResetHandler)
SECTIONS
{
. = 0;
_text = .;
startup : ALIGN(16) SUBALIGN(16)
{
KEEP(*(vectors))
} > flash
constructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__init_array_end = .);
} > flash
destructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__fini_array_start = .);
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
PROVIDE(__fini_array_end = .);
} > flash
.text : ALIGN(16) SUBALIGN(16)
{
*(.text.startup.*)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > flash
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > flash
.eh_frame_hdr :
{
*(.eh_frame_hdr)
} > flash
.eh_frame : ONLY_IF_RO
{
*(.eh_frame)
} > flash
.textalign : ONLY_IF_RO
{
. = ALIGN(8);
} > flash
. = ALIGN(4);
_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__ = .;
} > ram
.data ALIGN(4) : AT (_textdata)
{
. = ALIGN(4);
PROVIDE(_data = .);
*(.data)
*(.data.*)
*(.ramtext)
. = ALIGN(4);
PROVIDE(_edata = .);
} > ram
_textend = LOADADDR(.data) + SIZEOF(.data);
.bss ALIGN(4) : ALIGN(4)
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
PROVIDE(_bss_end = .);
} > ram
}
PROVIDE(end = .);
_end = .;
__heap_base__ = _end;
__heap_end__ = __ram_end__;

View File

@ -0,0 +1,146 @@
/*
ChibiOS/RT - Copyright (C) 2006-2013 Giovanni Di Sirio
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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.
*/
/*
* LPC43xx M4 memory setup.
*/
__main_stack_size__ = 0x0400; /* Exceptions/interrupts stack */
__process_stack_size__ = 0x1000; /* main() stack */
MEMORY
{
flash : org = 0x00000000, len = 96k /* Local SRAM @ 0x10000000 */
ram : org = 0x10080000, len = 32k /* Local SRAM @ 0x10080000 */
}
__ram_start__ = ORIGIN(ram);
__ram_size__ = LENGTH(ram);
__ram_end__ = __ram_start__ + __ram_size__;
ENTRY(ResetHandler)
SECTIONS
{
. = 0;
_text = .;
startup : ALIGN(16) SUBALIGN(16)
{
KEEP(*(vectors))
} > flash
constructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__init_array_start = .);
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
PROVIDE(__init_array_end = .);
} > flash
destructors : ALIGN(4) SUBALIGN(4)
{
PROVIDE(__fini_array_start = .);
KEEP(*(.fini_array))
KEEP(*(SORT(.fini_array.*)))
PROVIDE(__fini_array_end = .);
} > flash
.text : ALIGN(16) SUBALIGN(16)
{
*(.text.startup.*)
*(.text)
*(.text.*)
*(.rodata)
*(.rodata.*)
*(.glue_7t)
*(.glue_7)
*(.gcc*)
} > flash
.ARM.extab :
{
*(.ARM.extab* .gnu.linkonce.armextab.*)
} > flash
.ARM.exidx : {
PROVIDE(__exidx_start = .);
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
PROVIDE(__exidx_end = .);
} > flash
.eh_frame_hdr :
{
*(.eh_frame_hdr)
} > flash
.eh_frame : ONLY_IF_RO
{
*(.eh_frame)
} > flash
.textalign : ONLY_IF_RO
{
. = ALIGN(8);
} > flash
. = ALIGN(4);
_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__ = .;
} > ram
.data ALIGN(4) : AT (_textdata)
{
. = ALIGN(4);
PROVIDE(_data = .);
*(.data)
*(.data.*)
*(.ramtext)
. = ALIGN(4);
PROVIDE(_edata = .);
} > ram
.bss ALIGN(4) : ALIGN(4)
{
. = ALIGN(4);
PROVIDE(_bss_start = .);
*(.bss)
*(.bss.*)
*(COMMON)
. = ALIGN(4);
PROVIDE(_bss_end = .);
} > ram
}
PROVIDE(end = .);
_end = .;
__heap_base__ = _end;
__heap_end__ = __ram_end__;

View File

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

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_PORTAPACK)/os/ports/GCC/ARMCMx/LPC43xx_M4/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_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M4
PORTLD = ${CHIBIOS_PORTAPACK}/os/ports/GCC/ARMCMx/LPC43xx_M4/ld

View File

@ -0,0 +1,257 @@
/*
ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
2011,2012,2013 Giovanni Di Sirio.
Copyright (C) 2014 Jared Boone, ShareBrained Technology
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/>.
---
A special exception to the GPL can be applied should you wish to distribute
a combined work that includes ChibiOS/RT, without being obliged to provide
the source code for any proprietary components. See the file exception.txt
for full details of how and when the exception can be applied.
*/
/**
* @file GCC/ARMCMx/LPC43xx_M4/vectors.c
* @brief Interrupt vectors for the LPC43xx M4 family.
*
* @defgroup ARMCMx_LPC43xx_M4_VECTORS LPC43xx Interrupt Vectors
* @ingroup ARMCMx_SPECIFIC
* @details Interrupt vectors for the LPC43xx M4 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[53];
} 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 STM32 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,
VectorD0, VectorD4, VectorD8, VectorDC,
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) {
#if CH_DBG_ENABLED
chDbgPanic("Unhandled");
#else
while (TRUE)
;
#endif
}
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")));
/** @} */

View File

@ -0,0 +1,11 @@
# FATFS files.
set(FATFSSRC
${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_diskio.c
${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_syscall.c
${CHIBIOS_PORTAPACK}/ext/fatfs/src/ff.c
${CHIBIOS_PORTAPACK}/ext/fatfs/src/option/unicode.c
)
set(FATFSINC
${CHIBIOS_PORTAPACK}/ext/fatfs/src
)

View File

@ -0,0 +1,7 @@
# FATFS files.
FATFSSRC = ${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_diskio.c \
${CHIBIOS_PORTAPACK}/os/various/fatfs_bindings/fatfs_syscall.c \
${CHIBIOS_PORTAPACK}/ext/fatfs/src/ff.c \
${CHIBIOS_PORTAPACK}/ext/fatfs/src/option/unicode.c
FATFSINC = ${CHIBIOS_PORTAPACK}/ext/fatfs/src

View File

@ -0,0 +1,270 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "ch.h"
#include "hal.h"
#include <string.h>
#include "diskio.h"
#if HAL_USE_MMC_SPI && HAL_USE_SDC
#error "cannot specify both MMC_SPI and SDC drivers"
#endif
#if HAL_USE_MMC_SPI
extern MMCDriver MMCD1;
#elif HAL_USE_SDC
extern SDCDriver SDCD1;
#else
#error "MMC_SPI or SDC driver must be specified"
#endif
#if HAL_USE_RTC
#include "chrtclib.h"
extern RTCDriver RTCD1;
#endif
/* Definitions of physical drive number for each drive */
#define MMC 0
#define SDC 0
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&MMCD1) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&MMCD1))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&SDCD1) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&SDCD1))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
DSTATUS stat;
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&MMCD1) != BLK_READY)
stat |= STA_NOINIT;
if (mmcIsWriteProtected(&MMCD1))
stat |= STA_PROTECT;
return stat;
#else
case SDC:
stat = 0;
/* It is initialized externally, just reads the status.*/
if (blkGetDriverState(&SDCD1) != BLK_READY)
stat |= STA_NOINIT;
if (sdcIsWriteProtected(&SDCD1))
stat |= STA_PROTECT;
return stat;
#endif
}
return STA_NOINIT;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&MMCD1) != BLK_READY)
return RES_NOTRDY;
if (mmcStartSequentialRead(&MMCD1, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialRead(&MMCD1, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialRead(&MMCD1))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY;
if (sdcRead(&SDCD1, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_write (
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
if (blkGetDriverState(&MMCD1) != BLK_READY)
return RES_NOTRDY;
if (mmcIsWriteProtected(&MMCD1))
return RES_WRPRT;
if (mmcStartSequentialWrite(&MMCD1, sector))
return RES_ERROR;
while (count > 0) {
if (mmcSequentialWrite(&MMCD1, buff))
return RES_ERROR;
buff += MMCSD_BLOCK_SIZE;
count--;
}
if (mmcStopSequentialWrite(&MMCD1))
return RES_ERROR;
return RES_OK;
#else
case SDC:
if (blkGetDriverState(&SDCD1) != BLK_READY)
return RES_NOTRDY;
if (sdcWrite(&SDCD1, sector, buff, count))
return RES_ERROR;
return RES_OK;
#endif
}
return RES_PARERR;
}
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
DRESULT disk_ioctl (
BYTE pdrv, /* Physical drive nmuber (0..) */
BYTE cmd, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
switch (pdrv) {
#if HAL_USE_MMC_SPI
case MMC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
case MMC_GET_TYPE:
*((BYTE *)buff) = SDCD1.cardmode;
return RES_OK;
case MMC_GET_CSD:
memcpy(buff, &SDCD1.csd, sizeof(SDCD1.csd));
return RES_OK;
#if _USE_ERASE
case CTRL_ERASE_SECTOR:
mmcErase(&MMCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#else
case SDC:
switch (cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD *)buff) = mmcsdGetCardCapacity(&SDCD1);
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD *)buff) = MMCSD_BLOCK_SIZE;
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD *)buff) = 1; /* Unknown, TODO: implement? */
return RES_OK;
case MMC_GET_TYPE:
*((BYTE *)buff) = SDCD1.cardmode;
return RES_OK;
case MMC_GET_CSD:
memcpy(buff, &SDCD1.csd, sizeof(SDCD1.csd));
return RES_OK;
#if _USE_ERASE
case CTRL_ERASE_SECTOR:
sdcErase(&SDCD1, *((DWORD *)buff), *((DWORD *)buff + 1));
return RES_OK;
#endif
default:
return RES_PARERR;
}
#endif
}
return RES_PARERR;
}
DWORD get_fattime(void) {
#if HAL_USE_RTC
return rtcGetTimeFat(&RTCD1);
#else
return ((uint32_t)0 | (1 << 16)) | (1 << 21); /* wrong but valid time */
#endif
}

View File

@ -0,0 +1,84 @@
/*
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.
*/
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs R0.08b */
/* (C)ChaN, 2011 */
/*------------------------------------------------------------------------*/
#include "ch.h"
#include "ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Static array of Synchronization Objects */
/*------------------------------------------------------------------------*/
static Semaphore ff_sem[_VOLUMES];
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
int ff_cre_syncobj(BYTE vol, _SYNC_t *sobj) {
*sobj = &ff_sem[vol];
chSemInit(*sobj, 1);
return TRUE;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
int ff_del_syncobj(_SYNC_t sobj) {
chSemReset(sobj, 0);
return TRUE;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
int ff_req_grant(_SYNC_t sobj) {
msg_t msg = chSemWaitTimeout(sobj, (systime_t)_FS_TIMEOUT);
return msg == RDY_OK;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
void ff_rel_grant(_SYNC_t sobj) {
chSemSignal(sobj);
}
#endif /* _FS_REENTRANT */
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
void *ff_memalloc(UINT size) {
return chHeapAlloc(NULL, size);
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree(void *mblock) {
chHeapFree(mblock);
}
#endif /* _USE_LFN == 3 */

View File

@ -0,0 +1,6 @@
This directory contains the ChibiOS/RT "official" bindings with the FatFS
library by ChaN: http://elm-chan.org
In order to use FatFS within ChibiOS/RT project, unzip FatFS under
./ext/fatfs then include $(CHIBIOS)/os/various/fatfs_bindings/fatfs.mk
in your makefile.