aboutsummaryrefslogtreecommitdiffstats
path: root/os/hal/platforms/STM32
diff options
context:
space:
mode:
Diffstat (limited to 'os/hal/platforms/STM32')
-rw-r--r--os/hal/platforms/STM32/adc_lld.c104
-rw-r--r--os/hal/platforms/STM32/adc_lld.h61
-rw-r--r--os/hal/platforms/STM32/can_lld.c143
-rw-r--r--os/hal/platforms/STM32/can_lld.h83
-rw-r--r--os/hal/platforms/STM32/core_cm3.h3
-rw-r--r--os/hal/platforms/STM32/gpt_lld.c417
-rw-r--r--os/hal/platforms/STM32/gpt_lld.h256
-rw-r--r--os/hal/platforms/STM32/hal_lld.c68
-rw-r--r--os/hal/platforms/STM32/hal_lld.h7
-rw-r--r--os/hal/platforms/STM32/hal_lld_f100.h3
-rw-r--r--os/hal/platforms/STM32/hal_lld_f103.h13
-rw-r--r--os/hal/platforms/STM32/hal_lld_f105_f107.h142
-rw-r--r--os/hal/platforms/STM32/icu_lld.c425
-rw-r--r--os/hal/platforms/STM32/icu_lld.h290
-rw-r--r--os/hal/platforms/STM32/pal_lld.c18
-rw-r--r--os/hal/platforms/STM32/pal_lld.h10
-rw-r--r--os/hal/platforms/STM32/platform.dox116
-rw-r--r--os/hal/platforms/STM32/platform.mk3
-rw-r--r--os/hal/platforms/STM32/pwm_lld.c249
-rw-r--r--os/hal/platforms/STM32/pwm_lld.h238
-rw-r--r--os/hal/platforms/STM32/sdc_lld.c722
-rw-r--r--os/hal/platforms/STM32/sdc_lld.h203
-rw-r--r--os/hal/platforms/STM32/serial_lld.c3
-rw-r--r--os/hal/platforms/STM32/serial_lld.h3
-rw-r--r--os/hal/platforms/STM32/spi_lld.c269
-rw-r--r--os/hal/platforms/STM32/spi_lld.h67
-rw-r--r--os/hal/platforms/STM32/stm32_dma.c398
-rw-r--r--os/hal/platforms/STM32/stm32_dma.h48
-rw-r--r--os/hal/platforms/STM32/stm32_usb.h10
-rw-r--r--os/hal/platforms/STM32/stm32f10x.h485
-rw-r--r--os/hal/platforms/STM32/uart_lld.c385
-rw-r--r--os/hal/platforms/STM32/uart_lld.h89
-rw-r--r--os/hal/platforms/STM32/usb_lld.c517
-rw-r--r--os/hal/platforms/STM32/usb_lld.h236
34 files changed, 4558 insertions, 1526 deletions
diff --git a/os/hal/platforms/STM32/adc_lld.c b/os/hal/platforms/STM32/adc_lld.c
index 91fd8a6e8..8a8027e55 100644
--- a/os/hal/platforms/STM32/adc_lld.c
+++ b/os/hal/platforms/STM32/adc_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -47,39 +48,35 @@ ADCDriver ADCD1;
/* Driver local functions. */
/*===========================================================================*/
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-#if STM32_ADC_USE_ADC1 || defined(__DOXYGEN__)
/**
- * @brief ADC1 DMA interrupt handler (channel 1).
+ * @brief Shared ADC DMA ISR service routine.
*
- * @isr
+ * @param[in] adcp pointer to the @p ADCDriver object
+ * @param[in] flags pre-shifted content of the ISR register
*/
-CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) {
- uint32_t isr;
+static void adc_lld_serve_rx_interrupt(ADCDriver *adcp, uint32_t flags) {
- CH_IRQ_PROLOGUE();
-
- isr = STM32_DMA1->ISR;
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_1);
- if ((isr & DMA_ISR_TEIF1) != 0) {
- /* DMA error processing.*/
- STM32_ADC1_DMA_ERROR_HOOK();
+ /* DMA errors handling.*/
+#if defined(STM32_ADC_DMA_ERROR_HOOK)
+ if ((flags & DMA_ISR_TEIF1) != 0) {
+ STM32_ADC_DMA_ERROR_HOOK(spip);
}
- if ((isr & DMA_ISR_HTIF1) != 0) {
+#else
+ (void)flags;
+#endif
+ if ((flags & DMA_ISR_HTIF1) != 0) {
/* Half transfer processing.*/
- _adc_isr_half_code(&ADCD1);
+ _adc_isr_half_code(adcp);
}
- if ((isr & DMA_ISR_TCIF1) != 0) {
+ if ((flags & DMA_ISR_TCIF1) != 0) {
/* Transfer complete processing.*/
- _adc_isr_full_code(&ADCD1);
+ _adc_isr_full_code(adcp);
}
-
- CH_IRQ_EPILOGUE();
}
-#endif
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
@@ -93,15 +90,11 @@ CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) {
void adc_lld_init(void) {
#if STM32_ADC_USE_ADC1
- /* ADC reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB2RSTR = RCC_APB2RSTR_ADC1RST;
- RCC->APB2RSTR = 0;
-
/* Driver initialization.*/
adcObjectInit(&ADCD1);
- ADCD1.ad_adc = ADC1;
- ADCD1.ad_dmachp = STM32_DMA1_CH1;
- ADCD1.ad_dmaccr = (STM32_ADC_ADC1_DMA_PRIORITY << 12) |
+ ADCD1.adc = ADC1;
+ ADCD1.dmachp = STM32_DMA1_CH1;
+ ADCD1.dmaccr = (STM32_ADC_ADC1_DMA_PRIORITY << 12) |
DMA_CCR1_EN | DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 |
DMA_CCR1_MINC | DMA_CCR1_TCIE | DMA_CCR1_TEIE;
@@ -136,21 +129,22 @@ void adc_lld_init(void) {
void adc_lld_start(ADCDriver *adcp) {
/* If in stopped state then enables the ADC and DMA clocks.*/
- if (adcp->ad_state == ADC_STOP) {
+ if (adcp->state == ADC_STOP) {
#if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_1,
+ (stm32_dmaisr_t)adc_lld_serve_rx_interrupt, (void *)adcp);
NVICEnableVector(DMA1_Channel1_IRQn,
CORTEX_PRIORITY_MASK(STM32_ADC_ADC1_IRQ_PRIORITY));
- dmaChannelSetPeripheral(adcp->ad_dmachp, &ADC1->DR);
+ dmaChannelSetPeripheral(adcp->dmachp, &ADC1->DR);
RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;
}
#endif
/* ADC setup, the calibration procedure has already been performed
during initialization.*/
- adcp->ad_adc->CR1 = ADC_CR1_SCAN;
- adcp->ad_adc->CR2 = 0;
+ adcp->adc->CR1 = ADC_CR1_SCAN;
+ adcp->adc->CR2 = 0;
}
}
@@ -164,13 +158,13 @@ void adc_lld_start(ADCDriver *adcp) {
void adc_lld_stop(ADCDriver *adcp) {
/* If in ready state then disables the ADC clock.*/
- if (adcp->ad_state == ADC_READY) {
+ if (adcp->state == ADC_READY) {
#if STM32_ADC_USE_ADC1
if (&ADCD1 == adcp) {
ADC1->CR1 = 0;
ADC1->CR2 = 0;
NVICDisableVector(DMA1_Channel1_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_1);
RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN;
}
#endif
@@ -186,34 +180,34 @@ void adc_lld_stop(ADCDriver *adcp) {
*/
void adc_lld_start_conversion(ADCDriver *adcp) {
uint32_t ccr, n;
- const ADCConversionGroup *grpp = adcp->ad_grpp;
+ const ADCConversionGroup *grpp = adcp->grpp;
/* DMA setup.*/
- ccr = adcp->ad_dmaccr;
- if (grpp->acg_circular)
+ ccr = adcp->dmaccr;
+ if (grpp->circular)
ccr |= DMA_CCR1_CIRC;
- if (adcp->ad_depth > 1) {
+ if (adcp->depth > 1) {
/* If the buffer depth is greater than one then the half transfer interrupt
interrupt is enabled in order to allows streaming processing.*/
ccr |= DMA_CCR1_HTIE;
- n = (uint32_t)grpp->acg_num_channels * (uint32_t)adcp->ad_depth;
+ n = (uint32_t)grpp->num_channels * (uint32_t)adcp->depth;
}
else
- n = (uint32_t)grpp->acg_num_channels;
- dmaChannelSetup(adcp->ad_dmachp, n, adcp->ad_samples, ccr);
+ n = (uint32_t)grpp->num_channels;
+ dmaChannelSetup(adcp->dmachp, n, adcp->samples, ccr);
/* ADC setup.*/
- adcp->ad_adc->CR1 = grpp->acg_cr1 | ADC_CR1_SCAN;
- adcp->ad_adc->CR2 = grpp->acg_cr2 | ADC_CR2_DMA |
+ adcp->adc->CR1 = grpp->cr1 | ADC_CR1_SCAN;
+ adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA |
ADC_CR2_CONT | ADC_CR2_ADON;
- adcp->ad_adc->SMPR1 = grpp->acg_smpr1;
- adcp->ad_adc->SMPR2 = grpp->acg_smpr2;
- adcp->ad_adc->SQR1 = grpp->acg_sqr1;
- adcp->ad_adc->SQR2 = grpp->acg_sqr2;
- adcp->ad_adc->SQR3 = grpp->acg_sqr3;
+ adcp->adc->SMPR1 = grpp->smpr1;
+ adcp->adc->SMPR2 = grpp->smpr2;
+ adcp->adc->SQR1 = grpp->sqr1;
+ adcp->adc->SQR2 = grpp->sqr2;
+ adcp->adc->SQR3 = grpp->sqr3;
/* ADC start by writing ADC_CR2_ADON a second time.*/
- adcp->ad_adc->CR2 = grpp->acg_cr2 | ADC_CR2_DMA |
+ adcp->adc->CR2 = grpp->cr2 | ADC_CR2_DMA |
ADC_CR2_CONT | ADC_CR2_ADON;
}
@@ -226,8 +220,8 @@ void adc_lld_start_conversion(ADCDriver *adcp) {
*/
void adc_lld_stop_conversion(ADCDriver *adcp) {
- dmaChannelDisable(adcp->ad_dmachp);
- adcp->ad_adc->CR2 = 0;
+ dmaChannelDisable(adcp->dmachp);
+ adcp->adc->CR2 = 0;
}
#endif /* HAL_USE_ADC */
diff --git a/os/hal/platforms/STM32/adc_lld.h b/os/hal/platforms/STM32/adc_lld.h
index 876560fca..ce93e60ed 100644
--- a/os/hal/platforms/STM32/adc_lld.h
+++ b/os/hal/platforms/STM32/adc_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -82,7 +83,7 @@
* @brief ADC1 DMA priority (0..3|lowest..highest).
*/
#if !defined(STM32_ADC_ADC1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_ADC_ADC1_DMA_PRIORITY 3
+#define STM32_ADC_ADC1_DMA_PRIORITY 2
#endif
/**
@@ -93,12 +94,12 @@
#endif
/**
- * @brief ADC1 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
+ * @brief ADC DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
*/
-#if !defined(STM32_ADC1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()
+#if !defined(STM32_ADC_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_ADC_DMA_ERROR_HOOK(adcp) chSysHalt()
#endif
/*===========================================================================*/
@@ -113,6 +114,10 @@
#error "ADC driver activated but no ADC peripheral assigned"
#endif
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@@ -154,56 +159,56 @@ typedef struct {
/**
* @brief Enables the circular buffer mode for the group.
*/
- bool_t acg_circular;
+ bool_t circular;
/**
* @brief Number of the analog channels belonging to the conversion group.
*/
- adc_channels_num_t acg_num_channels;
+ adc_channels_num_t num_channels;
/**
* @brief Callback function associated to the group or @p NULL.
*/
- adccallback_t acg_endcb;
+ adccallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief ADC CR1 register initialization data.
* @note All the required bits must be defined into this field except
* @p ADC_CR1_SCAN that is enforced inside the driver.
*/
- uint32_t acg_cr1;
+ uint32_t cr1;
/**
* @brief ADC CR2 register initialization data.
* @note All the required bits must be defined into this field except
* @p ADC_CR2_DMA, @p ADC_CR2_CONT and @p ADC_CR2_ADON that are
* enforced inside the driver.
*/
- uint32_t acg_cr2;
+ uint32_t cr2;
/**
* @brief ADC SMPR1 register initialization data.
* @details In this field must be specified the sample times for channels
* 10...17.
*/
- uint32_t acg_smpr1;
+ uint32_t smpr1;
/**
* @brief ADC SMPR2 register initialization data.
* @details In this field must be specified the sample times for channels
* 0...9.
*/
- uint32_t acg_smpr2;
+ uint32_t smpr2;
/**
* @brief ADC SQR1 register initialization data.
* @details Conversion group sequence 13...16 + sequence length.
*/
- uint32_t acg_sqr1;
+ uint32_t sqr1;
/**
* @brief ADC SQR2 register initialization data.
* @details Conversion group sequence 7...12.
*/
- uint32_t acg_sqr2;
+ uint32_t sqr2;
/**
* @brief ADC SQR3 register initialization data.
* @details Conversion group sequence 0...6.
*/
- uint32_t acg_sqr3;
+ uint32_t sqr3;
} ADCConversionGroup;
/**
@@ -221,37 +226,37 @@ struct ADCDriver {
/**
* @brief Driver state.
*/
- adcstate_t ad_state;
+ adcstate_t state;
/**
* @brief Current configuration data.
*/
- const ADCConfig *ad_config;
+ const ADCConfig *config;
/**
* @brief Current samples buffer pointer or @p NULL.
*/
- adcsample_t *ad_samples;
+ adcsample_t *samples;
/**
* @brief Current samples buffer depth or @p 0.
*/
- size_t ad_depth;
+ size_t depth;
/**
* @brief Current conversion group pointer or @p NULL.
*/
- const ADCConversionGroup *ad_grpp;
+ const ADCConversionGroup *grpp;
#if ADC_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
- Thread *ad_thread;
+ Thread *thread;
#endif
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
/**
* @brief Mutex protecting the peripheral.
*/
- Mutex ad_mutex;
+ Mutex mutex;
#elif CH_USE_SEMAPHORES
- Semaphore ad_semaphore;
+ Semaphore semaphore;
#endif
#endif /* ADC_USE_MUTUAL_EXCLUSION */
#if defined(ADC_DRIVER_EXT_FIELDS)
@@ -261,15 +266,15 @@ struct ADCDriver {
/**
* @brief Pointer to the ADCx registers block.
*/
- ADC_TypeDef *ad_adc;
+ ADC_TypeDef *adc;
/**
* @brief Pointer to the DMA registers block.
*/
- stm32_dma_channel_t *ad_dmachp;
+ stm32_dma_channel_t *dmachp;
/**
* @brief DMA CCR register bit mask.
*/
- uint32_t ad_dmaccr;
+ uint32_t dmaccr;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/can_lld.c b/os/hal/platforms/STM32/can_lld.c
index 24a944c0f..e180a87cb 100644
--- a/os/hal/platforms/STM32/can_lld.c
+++ b/os/hal/platforms/STM32/can_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -63,9 +64,9 @@ CH_IRQ_HANDLER(CAN1_TX_IRQHandler) {
/* No more events until a message is transmitted.*/
CAN1->TSR = CAN_TSR_RQCP0 | CAN_TSR_RQCP1 | CAN_TSR_RQCP2;
chSysLockFromIsr();
- while (chSemGetCounterI(&CAND1.cd_txsem) < 0)
- chSemSignalI(&CAND1.cd_txsem);
- chEvtBroadcastI(&CAND1.cd_txempty_event);
+ while (chSemGetCounterI(&CAND1.txsem) < 0)
+ chSemSignalI(&CAND1.txsem);
+ chEvtBroadcastI(&CAND1.txempty_event);
chSysUnlockFromIsr();
CH_IRQ_EPILOGUE();
@@ -86,9 +87,9 @@ CH_IRQ_HANDLER(CAN1_RX0_IRQHandler) {
/* No more receive events until the queue 0 has been emptied.*/
CAN1->IER &= ~CAN_IER_FMPIE0;
chSysLockFromIsr();
- while (chSemGetCounterI(&CAND1.cd_rxsem) < 0)
- chSemSignalI(&CAND1.cd_rxsem);
- chEvtBroadcastI(&CAND1.cd_rxfull_event);
+ while (chSemGetCounterI(&CAND1.rxsem) < 0)
+ chSemSignalI(&CAND1.rxsem);
+ chEvtBroadcastI(&CAND1.rxfull_event);
chSysUnlockFromIsr();
}
if ((rf0r & CAN_RF0R_FOVR0) > 0) {
@@ -96,7 +97,7 @@ CH_IRQ_HANDLER(CAN1_RX0_IRQHandler) {
CAN1->RF0R = CAN_RF0R_FOVR0;
canAddFlagsI(&CAND1, CAN_OVERFLOW_ERROR);
chSysLockFromIsr();
- chEvtBroadcastI(&CAND1.cd_error_event);
+ chEvtBroadcastI(&CAND1.error_event);
chSysUnlockFromIsr();
}
@@ -132,7 +133,7 @@ CH_IRQ_HANDLER(CAN1_SCE_IRQHandler) {
/* Wakeup event.*/
if (msr & CAN_MSR_WKUI) {
chSysLockFromIsr();
- chEvtBroadcastI(&CAND1.cd_wakeup_event);
+ chEvtBroadcastI(&CAND1.wakeup_event);
chSysUnlockFromIsr();
}
/* Error event.*/
@@ -146,7 +147,7 @@ CH_IRQ_HANDLER(CAN1_SCE_IRQHandler) {
flags |= CAN_FRAMING_ERROR;
chSysLockFromIsr();
canAddFlagsI(&CAND1, flags | (canstatus_t)(flags < 16));
- chEvtBroadcastI(&CAND1.cd_error_event);
+ chEvtBroadcastI(&CAND1.error_event);
chSysUnlockFromIsr();
}
@@ -165,13 +166,9 @@ CH_IRQ_HANDLER(CAN1_SCE_IRQHandler) {
void can_lld_init(void) {
#if STM32_CAN_USE_CAN1
- /* CAN reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_CAN1RST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
canObjectInit(&CAND1);
- CAND1.cd_can = CAN1;
+ CAND1.can = CAN1;
#endif
}
@@ -200,37 +197,37 @@ void can_lld_start(CANDriver *canp) {
#endif
/* Entering initialization mode. */
- canp->cd_state = CAN_STARTING;
- canp->cd_can->MCR = CAN_MCR_INRQ;
- while ((canp->cd_can->MSR & CAN_MSR_INAK) == 0)
+ canp->state = CAN_STARTING;
+ canp->can->MCR = CAN_MCR_INRQ;
+ while ((canp->can->MSR & CAN_MSR_INAK) == 0)
chThdSleepS(1);
/* BTR initialization.*/
- canp->cd_can->BTR = canp->cd_config->cc_btr;
+ canp->can->BTR = canp->config->btr;
/* MCR initialization.*/
- canp->cd_can->MCR = canp->cd_config->cc_mcr;
+ canp->can->MCR = canp->config->mcr;
/* Filters initialization.*/
- canp->cd_can->FMR |= CAN_FMR_FINIT;
- if (canp->cd_config->cc_num > 0) {
+ canp->can->FMR |= CAN_FMR_FINIT;
+ if (canp->config->num > 0) {
uint32_t i, fmask;
CAN_FilterRegister_TypeDef *cfp;
- canp->cd_can->FA1R = 0;
- canp->cd_can->FM1R = 0;
- canp->cd_can->FS1R = 0;
- canp->cd_can->FFA1R = 0;
- cfp = canp->cd_can->sFilterRegister;
+ canp->can->FA1R = 0;
+ canp->can->FM1R = 0;
+ canp->can->FS1R = 0;
+ canp->can->FFA1R = 0;
+ cfp = canp->can->sFilterRegister;
fmask = 1;
for (i = 0; i < CAN_MAX_FILTERS; i++) {
- if (i < canp->cd_config->cc_num) {
- if (canp->cd_config->cc_filters[i].cf_mode)
- canp->cd_can->FM1R |= fmask;
- if (canp->cd_config->cc_filters[i].cf_scale)
- canp->cd_can->FS1R |= fmask;
- if (canp->cd_config->cc_filters[i].cf_assignment)
- canp->cd_can->FFA1R |= fmask;
- cfp->FR1 = canp->cd_config->cc_filters[i].cf_register1;
- cfp->FR2 = canp->cd_config->cc_filters[i].cf_register2;
- canp->cd_can->FA1R |= fmask;
+ if (i < canp->config->num) {
+ if (canp->config->filters[i].mode)
+ canp->can->FM1R |= fmask;
+ if (canp->config->filters[i].scale)
+ canp->can->FS1R |= fmask;
+ if (canp->config->filters[i].assignment)
+ canp->can->FFA1R |= fmask;
+ cfp->FR1 = canp->config->filters[i].register1;
+ cfp->FR2 = canp->config->filters[i].register2;
+ canp->can->FA1R |= fmask;
}
else {
cfp->FR1 = 0;
@@ -245,16 +242,16 @@ void can_lld_start(CANDriver *canp) {
}
else {
/* Setup a default filter.*/
- canp->cd_can->sFilterRegister[0].FR1 = 0;
- canp->cd_can->sFilterRegister[0].FR2 = 0;
- canp->cd_can->FM1R = 0;
- canp->cd_can->FFA1R = 0;
- canp->cd_can->FS1R = 1;
- canp->cd_can->FA1R = 1;
+ canp->can->sFilterRegister[0].FR1 = 0;
+ canp->can->sFilterRegister[0].FR2 = 0;
+ canp->can->FM1R = 0;
+ canp->can->FFA1R = 0;
+ canp->can->FS1R = 1;
+ canp->can->FA1R = 1;
}
- canp->cd_can->FMR &= ~CAN_FMR_FINIT;
+ canp->can->FMR &= ~CAN_FMR_FINIT;
/* Interrupt sources initialization.*/
- canp->cd_can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
+ canp->can->IER = CAN_IER_TMEIE | CAN_IER_FMPIE0 | CAN_IER_FMPIE1 |
CAN_IER_WKUIE | CAN_IER_ERRIE | CAN_IER_LECIE |
CAN_IER_BOFIE | CAN_IER_EPVIE | CAN_IER_EWGIE |
CAN_IER_FOVIE0 | CAN_IER_FOVIE1;
@@ -270,7 +267,7 @@ void can_lld_start(CANDriver *canp) {
void can_lld_stop(CANDriver *canp) {
/* If in ready state then disables the CAN peripheral.*/
- if (canp->cd_state == CAN_READY) {
+ if (canp->state == CAN_READY) {
#if STM32_CAN_USE_CAN1
if (&CAND1 == canp) {
CAN1->MCR = 0x00010002; /* Register reset value. */
@@ -298,7 +295,7 @@ void can_lld_stop(CANDriver *canp) {
*/
bool_t can_lld_can_transmit(CANDriver *canp) {
- return (canp->cd_can->TSR & CAN_TSR_TME) != 0;
+ return (canp->can->TSR & CAN_TSR_TME) != 0;
}
/**
@@ -314,18 +311,18 @@ void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) {
CAN_TxMailBox_TypeDef *tmbp;
/* Pointer to a free transmission mailbox.*/
- tmbp = &canp->cd_can->sTxMailBox[(canp->cd_can->TSR & CAN_TSR_CODE) >> 24];
+ tmbp = &canp->can->sTxMailBox[(canp->can->TSR & CAN_TSR_CODE) >> 24];
/* Preparing the message.*/
- if (ctfp->cf_IDE)
- tir = ((uint32_t)ctfp->cf_EID << 3) | ((uint32_t)ctfp->cf_RTR << 1) |
+ if (ctfp->IDE)
+ tir = ((uint32_t)ctfp->EID << 3) | ((uint32_t)ctfp->RTR << 1) |
CAN_TI0R_IDE;
else
- tir = ((uint32_t)ctfp->cf_SID << 21) | ((uint32_t)ctfp->cf_RTR << 1);
- tmbp->TDTR = ctfp->cf_DLC;
- tmbp->TDLR = ctfp->cf_data32[0];
- tmbp->TDHR = ctfp->cf_data32[1];
- tmbp->TIR = tir | CAN_TI0R_TXRQ;
+ tir = ((uint32_t)ctfp->SID << 21) | ((uint32_t)ctfp->RTR << 1);
+ tmbp->TDTR = ctfp->DLC;
+ tmbp->TDLR = ctfp->data32[0];
+ tmbp->TDHR = ctfp->data32[1];
+ tmbp->TIR = tir | CAN_TI0R_TXRQ;
}
/**
@@ -341,7 +338,7 @@ void can_lld_transmit(CANDriver *canp, const CANTxFrame *ctfp) {
*/
bool_t can_lld_can_receive(CANDriver *canp) {
- return (canp->cd_can->RF0R & CAN_RF0R_FMP0) > 0;
+ return (canp->can->RF0R & CAN_RF0R_FMP0) > 0;
}
/**
@@ -356,27 +353,27 @@ void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) {
uint32_t r;
/* Fetches the message.*/
- r = canp->cd_can->sFIFOMailBox[0].RIR;
- crfp->cf_RTR = (r & CAN_RI0R_RTR) >> 1;
- crfp->cf_IDE = (r & CAN_RI0R_IDE) >> 2;
- if (crfp->cf_IDE)
- crfp->cf_EID = r >> 3;
+ r = canp->can->sFIFOMailBox[0].RIR;
+ crfp->RTR = (r & CAN_RI0R_RTR) >> 1;
+ crfp->IDE = (r & CAN_RI0R_IDE) >> 2;
+ if (crfp->IDE)
+ crfp->EID = r >> 3;
else
- crfp->cf_SID = r >> 21;
- r = canp->cd_can->sFIFOMailBox[0].RDTR;
- crfp->cf_DLC = r & CAN_RDT0R_DLC;
- crfp->cf_FMI = (uint8_t)(r >> 8);
- crfp->cf_TIME = (uint16_t)(r >> 16);
- crfp->cf_data32[0] = canp->cd_can->sFIFOMailBox[0].RDLR;
- crfp->cf_data32[1] = canp->cd_can->sFIFOMailBox[0].RDHR;
+ crfp->SID = r >> 21;
+ r = canp->can->sFIFOMailBox[0].RDTR;
+ crfp->DLC = r & CAN_RDT0R_DLC;
+ crfp->FMI = (uint8_t)(r >> 8);
+ crfp->TIME = (uint16_t)(r >> 16);
+ crfp->data32[0] = canp->can->sFIFOMailBox[0].RDLR;
+ crfp->data32[1] = canp->can->sFIFOMailBox[0].RDHR;
/* Releases the mailbox.*/
- canp->cd_can->RF0R = CAN_RF0R_RFOM0;
+ canp->can->RF0R = CAN_RF0R_RFOM0;
/* If the queue is empty re-enables the interrupt in order to generate
events again.*/
- if ((canp->cd_can->RF0R & CAN_RF0R_FMP0) == 0)
- canp->cd_can->IER |= CAN_IER_FMPIE0;
+ if ((canp->can->RF0R & CAN_RF0R_FMP0) == 0)
+ canp->can->IER |= CAN_IER_FMPIE0;
}
#if CAN_USE_SLEEP_MODE || defined(__DOXYGEN__)
@@ -389,7 +386,7 @@ void can_lld_receive(CANDriver *canp, CANRxFrame *crfp) {
*/
void can_lld_sleep(CANDriver *canp) {
- canp->cd_can->MCR |= CAN_MCR_SLEEP;
+ canp->can->MCR |= CAN_MCR_SLEEP;
}
/**
@@ -401,7 +398,7 @@ void can_lld_sleep(CANDriver *canp) {
*/
void can_lld_wakeup(CANDriver *canp) {
- canp->cd_can->MCR &= ~CAN_MCR_SLEEP;
+ canp->can->MCR &= ~CAN_MCR_SLEEP;
}
#endif /* CAN_USE_SLEEP_MODE */
diff --git a/os/hal/platforms/STM32/can_lld.h b/os/hal/platforms/STM32/can_lld.h
index 0d4c9b615..a9a086e5b 100644
--- a/os/hal/platforms/STM32/can_lld.h
+++ b/os/hal/platforms/STM32/can_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -121,22 +122,22 @@ typedef uint32_t canstatus_t;
*/
typedef struct {
struct {
- uint8_t cf_DLC:4; /**< @brief Data length. */
- uint8_t cf_RTR:1; /**< @brief Frame type. */
- uint8_t cf_IDE:1; /**< @brief Identifier type. */
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
};
union {
struct {
- uint32_t cf_SID:11; /**< @brief Standard identifier.*/
+ uint32_t SID:11; /**< @brief Standard identifier.*/
};
struct {
- uint32_t cf_EID:29; /**< @brief Extended identifier.*/
+ uint32_t EID:29; /**< @brief Extended identifier.*/
};
};
union {
- uint8_t cf_data8[8]; /**< @brief Frame data. */
- uint16_t cf_data16[4]; /**< @brief Frame data. */
- uint32_t cf_data32[2]; /**< @brief Frame data. */
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
};
} CANTxFrame;
@@ -147,26 +148,26 @@ typedef struct {
*/
typedef struct {
struct {
- uint8_t cf_FMI; /**< @brief Filter id. */
- uint16_t cf_TIME; /**< @brief Time stamp. */
+ uint8_t FMI; /**< @brief Filter id. */
+ uint16_t TIME; /**< @brief Time stamp. */
};
struct {
- uint8_t cf_DLC:4; /**< @brief Data length. */
- uint8_t cf_RTR:1; /**< @brief Frame type. */
- uint8_t cf_IDE:1; /**< @brief Identifier type. */
+ uint8_t DLC:4; /**< @brief Data length. */
+ uint8_t RTR:1; /**< @brief Frame type. */
+ uint8_t IDE:1; /**< @brief Identifier type. */
};
union {
struct {
- uint32_t cf_SID:11; /**< @brief Standard identifier.*/
+ uint32_t SID:11; /**< @brief Standard identifier.*/
};
struct {
- uint32_t cf_EID:29; /**< @brief Extended identifier.*/
+ uint32_t EID:29; /**< @brief Extended identifier.*/
};
};
union {
- uint8_t cf_data8[8]; /**< @brief Frame data. */
- uint16_t cf_data16[4]; /**< @brief Frame data. */
- uint32_t cf_data32[2]; /**< @brief Frame data. */
+ uint8_t data8[8]; /**< @brief Frame data. */
+ uint16_t data16[4]; /**< @brief Frame data. */
+ uint32_t data32[2]; /**< @brief Frame data. */
};
} CANRxFrame;
@@ -180,27 +181,27 @@ typedef struct {
* @note This bit represent the CAN_FM1R register bit associated to this
* filter (0=mask mode, 1=list mode).
*/
- uint32_t cf_mode:1;
+ uint32_t mode:1;
/**
* @brief Filter sclae.
* @note This bit represent the CAN_FS1R register bit associated to this
* filter (0=16 bits mode, 1=32 bits mode).
*/
- uint32_t cf_scale:1;
+ uint32_t scale:1;
/**
* @brief Filter mode.
* @note This bit represent the CAN_FFA1R register bit associated to this
* filter, must be set to zero in this version of the driver.
*/
- uint32_t cf_assignment:1;
+ uint32_t assignment:1;
/**
* @brief Filter register 1 (identifier).
*/
- uint32_t cf_register1;
+ uint32_t register1;
/**
- * @brief Filter register 2 (mask/identifier depending on cf_mode=0/1).
+ * @brief Filter register 2 (mask/identifier depending on mode=0/1).
*/
- uint32_t cf_register2;
+ uint32_t register2;
} CANFilter;
/**
@@ -212,25 +213,25 @@ typedef struct {
* @note Some bits in this register are enforced by the driver regardless
* their status in this field.
*/
- uint32_t cc_mcr;
+ uint32_t mcr;
/**
* @brief CAN BTR register initialization data.
* @note Some bits in this register are enforced by the driver regardless
* their status in this field.
*/
- uint32_t cc_btr;
+ uint32_t btr;
/**
* @brief Number of elements into the filters array.
* @note By setting this field to zero a default filter is enabled that
* allows all frames, this should be adequate for simple applications.
*/
- uint32_t cc_num;
+ uint32_t num;
/**
* @brief Pointer to an array of @p CANFilter structures.
- * @note This field can be set to @p NULL if the field @p cc_num is set to
+ * @note This field can be set to @p NULL if the field @p num is set to
* zero.
*/
- const CANFilter *cc_filters;
+ const CANFilter *filters;
} CANConfig;
/**
@@ -240,19 +241,19 @@ typedef struct {
/**
* @brief Driver state.
*/
- canstate_t cd_state;
+ canstate_t state;
/**
* @brief Current configuration data.
*/
- const CANConfig *cd_config;
+ const CANConfig *config;
/**
* @brief Transmission queue semaphore.
*/
- Semaphore cd_txsem;
+ Semaphore txsem;
/**
* @brief Receive queue semaphore.
*/
- Semaphore cd_rxsem;
+ Semaphore rxsem;
/**
* @brief One or more frames become available.
* @note After broadcasting this event it will not be broadcasted again
@@ -262,34 +263,34 @@ typedef struct {
* invoking @p chReceive() when listening to this event. This behavior
* minimizes the interrupt served by the system because CAN traffic.
*/
- EventSource cd_rxfull_event;
+ EventSource rxfull_event;
/**
* @brief One or more transmission slots become available.
*/
- EventSource cd_txempty_event;
+ EventSource txempty_event;
/**
* @brief A CAN bus error happened.
*/
- EventSource cd_error_event;
+ EventSource error_event;
/**
* @brief Error flags set when an error event is broadcasted.
*/
- canstatus_t cd_status;
+ canstatus_t status;
#if CAN_USE_SLEEP_MODE || defined (__DOXYGEN__)
/**
* @brief Entering sleep state event.
*/
- EventSource cd_sleep_event;
+ EventSource sleep_event;
/**
* @brief Exiting sleep state event.
*/
- EventSource cd_wakeup_event;
+ EventSource wakeup_event;
#endif /* CAN_USE_SLEEP_MODE */
/* End of the mandatory fields.*/
/**
* @brief Pointer to the CAN registers.
*/
- CAN_TypeDef *cd_can;
+ CAN_TypeDef *can;
} CANDriver;
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/core_cm3.h b/os/hal/platforms/STM32/core_cm3.h
index 5c75ec859..387221bc6 100644
--- a/os/hal/platforms/STM32/core_cm3.h
+++ b/os/hal/platforms/STM32/core_cm3.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
diff --git a/os/hal/platforms/STM32/gpt_lld.c b/os/hal/platforms/STM32/gpt_lld.c
new file mode 100644
index 000000000..8419cad68
--- /dev/null
+++ b/os/hal/platforms/STM32/gpt_lld.c
@@ -0,0 +1,417 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/gpt_lld.c
+ * @brief STM32 GPT subsystem low level driver source.
+ *
+ * @addtogroup GPT
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_GPT || defined(__DOXYGEN__)
+
+/* There are differences in vector names in the ST header for devices
+ including TIM15, TIM16, TIM17.*/
+#if STM32_HAS_TIM15
+#define TIM1_BRK_IRQn TIM1_BRK_TIM15_IRQn
+#endif
+#if STM32_HAS_TIM16
+#define TIM1_UP_IRQn TIM1_UP_TIM16_IRQn
+#endif
+#if STM32_HAS_TIM17
+#define TIM1_TRG_COM_IRQn TIM1_TRG_COM_TIM17_IRQn
+#endif
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief GPTD1 driver identifier.
+ * @note The driver GPTD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_GPT_USE_TIM1 || defined(__DOXYGEN__)
+GPTDriver GPTD1;
+#endif
+
+/**
+ * @brief GPTD2 driver identifier.
+ * @note The driver GPTD2 allocates the timer TIM2 when enabled.
+ */
+#if STM32_GPT_USE_TIM2 || defined(__DOXYGEN__)
+GPTDriver GPTD2;
+#endif
+
+/**
+ * @brief GPTD3 driver identifier.
+ * @note The driver GPTD3 allocates the timer TIM3 when enabled.
+ */
+#if STM32_GPT_USE_TIM3 || defined(__DOXYGEN__)
+GPTDriver GPTD3;
+#endif
+
+/**
+ * @brief GPTD4 driver identifier.
+ * @note The driver GPTD4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_GPT_USE_TIM4 || defined(__DOXYGEN__)
+GPTDriver GPTD4;
+#endif
+
+/**
+ * @brief GPTD5 driver identifier.
+ * @note The driver GPTD5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_GPT_USE_TIM5 || defined(__DOXYGEN__)
+GPTDriver GPTD5;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* 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->tim->SR = 0;
+ 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 STM32_GPT_USE_TIM1
+/**
+ * @brief TIM2 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM1_UP_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_GPT_USE_TIM1 */
+
+#if STM32_GPT_USE_TIM2
+/**
+ * @brief TIM2 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM2_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD2);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_GPT_USE_TIM2 */
+
+#if STM32_GPT_USE_TIM3
+/**
+ * @brief TIM3 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM3_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD3);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_GPT_USE_TIM3 */
+
+#if STM32_GPT_USE_TIM4
+/**
+ * @brief TIM4 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM4_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD4);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_GPT_USE_TIM4 */
+
+#if STM32_GPT_USE_TIM5
+/**
+ * @brief TIM5 interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM5_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ gpt_lld_serve_interrupt(&GPTD5);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_GPT_USE_TIM5 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level GPT driver initialization.
+ *
+ * @notapi
+ */
+void gpt_lld_init(void) {
+
+#if STM32_GPT_USE_TIM1
+ /* Driver initialization.*/
+ GPTD1.tim = TIM1;
+ gptObjectInit(&GPTD1);
+#endif
+
+#if STM32_GPT_USE_TIM2
+ /* Driver initialization.*/
+ GPTD2.tim = TIM2;
+ gptObjectInit(&GPTD2);
+#endif
+
+#if STM32_GPT_USE_TIM3
+ /* Driver initialization.*/
+ GPTD3.tim = TIM3;
+ gptObjectInit(&GPTD3);
+#endif
+
+#if STM32_GPT_USE_TIM4
+ /* Driver initialization.*/
+ GPTD4.tim = TIM4;
+ gptObjectInit(&GPTD4);
+#endif
+
+#if STM32_GPT_USE_TIM5
+ /* Driver initialization.*/
+ GPTD5.tim = TIM5;
+ gptObjectInit(&GPTD5);
+#endif
+}
+
+/**
+ * @brief Configures and activates the GPT peripheral.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_start(GPTDriver *gptp) {
+ uint16_t psc;
+
+ if (gptp->state == GPT_STOP) {
+ /* Clock activation.*/
+#if STM32_GPT_USE_TIM1
+ if (&GPTD1 == gptp) {
+ RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
+ RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
+ RCC->APB2RSTR = 0;
+ NVICEnableVector(TIM1_UP_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_GPT_TIM1_IRQ_PRIORITY));
+ gptp->clock = STM32_TIMCLK2;
+ }
+#endif
+#if STM32_GPT_USE_TIM2
+ if (&GPTD2 == gptp) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM2_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_GPT_TIM2_IRQ_PRIORITY));
+ gptp->clock = STM32_TIMCLK1;
+ }
+#endif
+#if STM32_GPT_USE_TIM3
+ if (&GPTD3 == gptp) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM3_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_GPT_TIM3_IRQ_PRIORITY));
+ gptp->clock = STM32_TIMCLK1;
+ }
+#endif
+#if STM32_GPT_USE_TIM4
+ if (&GPTD4 == gptp) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM4_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_GPT_TIM4_IRQ_PRIORITY));
+ gptp->clock = STM32_TIMCLK1;
+ }
+#endif
+
+#if STM32_GPT_USE_TIM5
+ if (&GPTD5 == gptp) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM5_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_GPT_TIM5_IRQ_PRIORITY));
+ gptp->clock = STM32_TIMCLK1;
+ }
+#endif
+ }
+
+ /* Prescaler value calculation.*/
+ psc = (uint16_t)((gptp->clock / gptp->config->frequency) - 1);
+ chDbgAssert(((uint32_t)(psc + 1) * gptp->config->frequency) == gptp->clock,
+ "gpt_lld_start(), #1", "invalid frequency");
+
+ /* Timer configuration.*/
+ gptp->tim->CR1 = 0; /* Initially stopped. */
+ gptp->tim->CR2 = TIM_CR2_CCDS; /* DMA on UE (if any). */
+ gptp->tim->PSC = psc; /* Prescaler value. */
+ gptp->tim->DIER = 0;
+}
+
+/**
+ * @brief Deactivates the GPT peripheral.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_stop(GPTDriver *gptp) {
+
+ if (gptp->state == GPT_READY) {
+ gptp->tim->CR1 = 0; /* Timer disabled. */
+ gptp->tim->DIER = 0; /* All IRQs disabled. */
+ gptp->tim->SR = 0; /* Clear eventual pending IRQs. */
+
+#if STM32_GPT_USE_TIM1
+ if (&GPTD1 == gptp) {
+ NVICDisableVector(TIM1_UP_IRQn);
+ RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ }
+#endif
+#if STM32_GPT_USE_TIM2
+ if (&GPTD2 == gptp) {
+ NVICDisableVector(TIM2_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM2EN;
+ }
+#endif
+#if STM32_GPT_USE_TIM3
+ if (&GPTD3 == gptp) {
+ NVICDisableVector(TIM3_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
+ }
+#endif
+#if STM32_GPT_USE_TIM4
+ if (&GPTD4 == gptp) {
+ NVICDisableVector(TIM4_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM4EN;
+ }
+#endif
+#if STM32_GPT_USE_TIM5
+ if (&GPTD5 == gptp) {
+ NVICDisableVector(TIM5_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
+ }
+#endif
+ }
+}
+
+/**
+ * @brief Starts the timer in continuous mode.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ * @param[in] interval period in ticks
+ *
+ * @notapi
+ */
+void gpt_lld_start_timer(GPTDriver *gptp, gptcnt_t interval) {
+
+ gptp->tim->ARR = interval - 1; /* Time constant. */
+ gptp->tim->EGR = TIM_EGR_UG; /* Update event. */
+ gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
+ gptp->tim->DIER = TIM_DIER_UIE; /* Update Event IRQ enabled. */
+ gptp->tim->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
+}
+
+/**
+ * @brief Stops the timer.
+ *
+ * @param[in] gptp pointer to the @p GPTDriver object
+ *
+ * @notapi
+ */
+void gpt_lld_stop_timer(GPTDriver *gptp) {
+
+ gptp->tim->CR1 = 0; /* Initially stopped. */
+ gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
+ gptp->tim->DIER = 0; /* Interrupts disabled. */
+}
+
+/**
+ * @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->tim->ARR = interval - 1; /* Time constant. */
+ gptp->tim->EGR = TIM_EGR_UG; /* Update event. */
+ gptp->tim->SR = 0; /* Clear pending IRQs (if any). */
+ gptp->tim->CR1 = TIM_CR1_OPM | TIM_CR1_URS | TIM_CR1_CEN;
+ while (!(gptp->tim->SR & TIM_SR_UIF))
+ ;
+}
+
+#endif /* HAL_USE_GPT */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/gpt_lld.h b/os/hal/platforms/STM32/gpt_lld.h
new file mode 100644
index 000000000..cf749077f
--- /dev/null
+++ b/os/hal/platforms/STM32/gpt_lld.h
@@ -0,0 +1,256 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/gpt_lld.h
+ * @brief STM32 GPT subsystem low level driver header.
+ *
+ * @addtogroup GPT
+ * @{
+ */
+
+#ifndef _GPT_LLD_H_
+#define _GPT_LLD_H_
+
+#if HAL_USE_GPT || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief GPTD1 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_GPT_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM1 TRUE
+#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(STM32_GPT_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM2 TRUE
+#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(STM32_GPT_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM3 TRUE
+#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(STM32_GPT_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM4 TRUE
+#endif
+
+/**
+ * @brief GPTD5 driver enable switch.
+ * @details If set to @p TRUE the support for GPTD5 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_GPT_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_GPT_USE_TIM5 TRUE
+#endif
+
+/**
+ * @brief GPTD1 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM1_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD2 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM2_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD3 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM3_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD4 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM4_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief GPTD5 interrupt priority level setting.
+ */
+#if !defined(STM32_GPT_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_GPT_TIM5_IRQ_PRIORITY 7
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_GPT_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_GPT_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if !STM32_GPT_USE_TIM1 && !STM32_GPT_USE_TIM2 && \
+ !STM32_GPT_USE_TIM3 && !STM32_GPT_USE_TIM4 && \
+ !STM32_GPT_USE_TIM5
+#error "GPT driver activated but no TIM peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief GPT frequency type.
+ */
+typedef uint32_t gptfreq_t;
+
+/**
+ * @brief GPT counter type.
+ */
+typedef uint16_t gptcnt_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ gptfreq_t frequency;
+ /**
+ * @brief Timer callback pointer.
+ * @note This callback is invoked on GPT counter events.
+ */
+ gptcallback_t callback;
+ /* End of the mandatory fields.*/
+} GPTConfig;
+
+/**
+ * @brief Structure representing a GPT driver.
+ */
+struct GPTDriver {
+ /**
+ * @brief Driver state.
+ */
+ gptstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const GPTConfig *config;
+#if defined(GPT_DRIVER_EXT_FIELDS)
+ GPT_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Timer base clock.
+ */
+ uint32_t clock;
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ TIM_TypeDef *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_GPT_USE_TIM1 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD1;
+#endif
+
+#if STM32_GPT_USE_TIM2 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD2;
+#endif
+
+#if STM32_GPT_USE_TIM3 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD3;
+#endif
+
+#if STM32_GPT_USE_TIM4 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD4;
+#endif
+
+#if STM32_GPT_USE_TIM5 && !defined(__DOXYGEN__)
+extern GPTDriver GPTD5;
+#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_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/hal_lld.c b/os/hal/platforms/STM32/hal_lld.c
index 8d8322033..9b4feb982 100644
--- a/os/hal/platforms/STM32/hal_lld.c
+++ b/os/hal/platforms/STM32/hal_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -57,6 +58,12 @@
*/
void hal_lld_init(void) {
+ /* Reset of all peripherals.*/
+ RCC->APB1RSTR = 0xFFFFFFFF;
+ RCC->APB2RSTR = 0xFFFFFFFF;
+ RCC->APB1RSTR = 0;
+ RCC->APB2RSTR = 0;
+
/* SysTick initialization using the system clock.*/
SysTick->LOAD = STM32_HCLK / CH_FREQUENCY - 1;
SysTick->VAL = 0;
@@ -64,7 +71,7 @@ void hal_lld_init(void) {
SysTick_CTRL_ENABLE_Msk |
SysTick_CTRL_TICKINT_Msk;
-#if HAL_USE_ADC || HAL_USE_SPI || HAL_USE_UART
+#if defined(STM32_DMA_REQUIRED)
dmaInit();
#endif
}
@@ -76,9 +83,10 @@ void hal_lld_init(void) {
*
* @special
*/
-#if defined(STM32F10X_LD) || defined(STM32F10X_MD) || \
- defined(STM32F10X_HD) || defined(STM32F10X_LD_VL) || \
- defined(STM32F10X_MD_VL) || defined(__DOXYGEN__)
+#if defined(STM32F10X_LD) || defined(STM32F10X_LD_VL) || \
+ defined(STM32F10X_MD) || defined(STM32F10X_MD_VL) || \
+ defined(STM32F10X_HD) || defined(STM32F10X_XL) || \
+ defined(__DOXYGEN__)
/*
* Clocks initialization for the LD, MD and HD sub-families.
*/
@@ -140,43 +148,51 @@ void stm32_clock_init(void) {
*/
void stm32_clock_init(void) {
- /* HSI setup, it enforces the reset situation in order to handle possible
- problems with JTAG probes and re-initializations.*/
+ /* HSI setup.*/
RCC->CR |= RCC_CR_HSION; /* Make sure HSI is ON. */
while (!(RCC->CR & RCC_CR_HSIRDY))
; /* Wait until HSI is stable. */
+ RCC->CFGR = 0;
RCC->CR &= RCC_CR_HSITRIM | RCC_CR_HSION; /* CR Reset value. */
- RCC->CFGR = 0; /* CFGR reset value. */
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI)
; /* Wait until HSI is the source.*/
- RCC->CFGR2 = 0;
- /* HSE setup, it is only performed if the HSE clock is selected as source
- of the system clock (directly or through the PLLs).*/
-#if (STM32_SW == STM32_SW_HSE) || \
- ((STM32_SW == STM32_SW_PLL) && (STM32_PLLSRC == STM32_PLLSRC_PREDIV1))
+ /* HSE setup, it is only performed if the current configuration uses
+ it somehow.*/
+#if STM32_ACTIVATE_PLL2 || \
+ STM32_ACTIVATE_PLL3 || \
+ (STM32_SW == STM32_SW_HSE) || \
+ ((STM32_PREDIV1SRC == STM32_PREDIV1SRC_HSE) && \
+ (STM32_PLLSRC == STM32_PLLSRC_PREDIV1))
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY))
; /* Waits until HSE is stable. */
#endif
- /* PLL2 setup, it is only performed if the PLL2 clock is selected as source
- for the PLL clock else it is left disabled.*/
-#if STM32_SW == STM32_SW_PLL
-#if STM32_PREDIV1SRC == STM32_PREDIV1SRC_PLL2
- RCC->CFGR2 |= STM32_PREDIV2 | STM32_PLL2MUL;
- RCC->CR |= RCC_CR_PLL2ON;
+ /* Settings of various dividers and multipliers in CFGR2.*/
+ RCC->CFGR2 = STM32_PLL3MUL | STM32_PLL2MUL | STM32_PREDIV2 |
+ STM32_PREDIV1 | STM32_PREDIV1SRC;
+
+ /* PLL2 setup, if activated.*/
+#if STM32_ACTIVATE_PLL2
+ RCC->CR |= RCC_CR_PLL2ON;
while (!(RCC->CR & RCC_CR_PLL2RDY))
- ; /* Waits until PLL is stable. */
+ ; /* Waits until PLL2 is stable. */
#endif
- /* PLL setup, it is only performed if the PLL is the selected source of
- the system clock else it is left disabled.*/
- RCC->CFGR2 |= STM32_PREDIV1 | STM32_PREDIV1SRC;
- RCC->CFGR |= STM32_PLLMUL | STM32_PLLSRC;
- RCC->CR |= RCC_CR_PLLON;
+ /* PLL3 setup, if activated.*/
+#if STM32_ACTIVATE_PLL3
+ RCC->CR |= RCC_CR_PLL3ON;
+ while (!(RCC->CR & RCC_CR_PLL3RDY))
+ ; /* Waits until PLL3 is stable. */
+#endif
+
+ /* PLL1 setup, if activated.*/
+#if STM32_ACTIVATE_PLL1
+ RCC->CFGR |= STM32_PLLMUL | STM32_PLLSRC;
+ RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY))
- ; /* Waits until PLL2 is stable. */
+ ; /* Waits until PLL1 is stable. */
#endif
/* Clock settings.*/
diff --git a/os/hal/platforms/STM32/hal_lld.h b/os/hal/platforms/STM32/hal_lld.h
index 0abac770c..b9c71dbbe 100644
--- a/os/hal/platforms/STM32/hal_lld.h
+++ b/os/hal/platforms/STM32/hal_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -31,7 +32,7 @@
* - STM32F10X_LD for Performance Low Density devices.
* - STM32F10X_MD for Performance Medium Density devices.
* - STM32F10X_HD for Performance High Density devices.
- * - STM32F10X_XD for Performance eXtra Density devices.
+ * - STM32F10X_XL for Performance eXtra Density devices.
* - STM32F10X_CL for Connectivity Line devices.
* .
*
@@ -395,7 +396,7 @@
#define STM32_HAS_USB TRUE
#define STM32_HAS_OTG1 FALSE
-#elif defined(STM32F10X_XD)
+#elif defined(STM32F10X_XL)
/*
* Capability flags for Performance Line eXtra Density devices.
*/
diff --git a/os/hal/platforms/STM32/hal_lld_f100.h b/os/hal/platforms/STM32/hal_lld_f100.h
index 1ce918079..571682e38 100644
--- a/os/hal/platforms/STM32/hal_lld_f100.h
+++ b/os/hal/platforms/STM32/hal_lld_f100.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
diff --git a/os/hal/platforms/STM32/hal_lld_f103.h b/os/hal/platforms/STM32/hal_lld_f103.h
index 6ea53571a..1f11da249 100644
--- a/os/hal/platforms/STM32/hal_lld_f103.h
+++ b/os/hal/platforms/STM32/hal_lld_f103.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -127,28 +128,19 @@
#define TIM1_CC_IRQHandler VectorAC /**< TIM1 Capture Compare. */
#define TIM2_IRQHandler VectorB0 /**< TIM2. */
#define TIM3_IRQHandler VectorB4 /**< TIM3. */
-#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
#define TIM4_IRQHandler VectorB8 /**< TIM4. */
-#endif
#define I2C1_EV_IRQHandler VectorBC /**< I2C1 Event. */
#define I2C1_ER_IRQHandler VectorC0 /**< I2C1 Error. */
-#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
#define I2C2_EV_IRQHandler VectorC4 /**< I2C2 Event. */
#define I2C2_ER_IRQHandler VectorC8 /**< I2C2 Error. */
-#endif
#define SPI1_IRQHandler VectorCC /**< SPI1. */
-#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
#define SPI2_IRQHandler VectorD0 /**< SPI2. */
-#endif
#define USART1_IRQHandler VectorD4 /**< USART1. */
#define USART2_IRQHandler VectorD8 /**< USART2. */
-#if !defined(STM32F10X_LD) || defined(__DOXYGEN__)
#define USART3_IRQHandler VectorDC /**< USART3. */
-#endif
#define EXTI15_10_IRQHandler VectorE0 /**< EXTI Line 15..10. */
#define RTCAlarm_IRQHandler VectorE4 /**< RTC Alarm through EXTI. */
#define USBWakeUp_IRQHandler VectorE8 /**< USB Wakeup from suspend. */
-#if defined(STM32F10X_HD) || defined(__DOXYGEN__)
#define TIM8_BRK_IRQHandler VectorEC /**< TIM8 Break. */
#define TIM8_UP_IRQHandler VectorF0 /**< TIM8 Update. */
#define TIM8_TRG_COM_IRQHandler VectorF4 /**< TIM8 Trigger and
@@ -167,7 +159,6 @@
#define DMA2_Ch2_IRQHandler Vector124 /**< DMA2 Channel2. */
#define DMA2_Ch3_IRQHandler Vector128 /**< DMA2 Channel3. */
#define DMA2_Ch4_5_IRQHandler Vector12C /**< DMA2 Channel4 & Channel5. */
-#endif
/*===========================================================================*/
/* Driver pre-compile time settings. */
diff --git a/os/hal/platforms/STM32/hal_lld_f105_f107.h b/os/hal/platforms/STM32/hal_lld_f105_f107.h
index d4477e705..ce8147ae0 100644
--- a/os/hal/platforms/STM32/hal_lld_f105_f107.h
+++ b/os/hal/platforms/STM32/hal_lld_f105_f107.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -171,9 +172,34 @@
/*===========================================================================*/
/**
+ * @brief PLL1 main switch.
+ * @note If this constant is set to @p TRUE then the PLL1 is initialized
+ * and started.
+ */
+#if !defined(STM32_ACTIVATE_PLL1) || defined(__DOXYGEN__)
+#define STM32_ACTIVATE_PLL1 TRUE
+#endif
+
+/**
+ * @brief PLL2 main switch.
+ * @note If this constant is set to @p TRUE then the PLL2 is initialized
+ * and started.
+ */
+#if !defined(STM32_ACTIVATE_PLL2) || defined(__DOXYGEN__)
+#define STM32_ACTIVATE_PLL2 TRUE
+#endif
+
+/**
+ * @brief PLL3 main switch.
+ * @note If this constant is set to @p TRUE then the PLL3 is initialized
+ * and started.
+ */
+#if !defined(STM32_ACTIVATE_PLL3) || defined(__DOXYGEN__)
+#define STM32_ACTIVATE_PLL3 TRUE
+#endif
+
+/**
* @brief Main clock source selection.
- * @note If the selected clock source is not the PLL then the PLL is not
- * initialized and started.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
*/
@@ -183,8 +209,6 @@
/**
* @brief Clock source for the PLL.
- * @note This setting has only effect if the PLL is selected as the
- * system clock source.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
*/
@@ -194,8 +218,6 @@
/**
* @brief PREDIV1 clock source.
- * @note This setting has only effect if the PLL is selected as the
- * system clock source.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
*/
@@ -205,8 +227,6 @@
/**
* @brief PREDIV1 division factor.
- * @note This setting has only effect if the PLL is selected as the
- * system clock source.
* @note The allowed range is 1...16.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
@@ -227,8 +247,6 @@
/**
* @brief PREDIV2 division factor.
- * @note This setting has only effect if the PLL2 is selected as the
- * clock source for the PLL.
* @note The allowed range is 1...16.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
@@ -247,6 +265,15 @@
#endif
/**
+ * @brief PLL3 multiplier value.
+ * @note The default value is calculated for a 50MHz clock from
+ * a 25MHz crystal.
+ */
+#if !defined(STM32_PLL3MUL_VALUE) || defined(__DOXYGEN__)
+#define STM32_PLL3MUL_VALUE 10
+#endif
+
+/**
* @brief AHB prescaler value.
* @note The default value is calculated for a 72MHz system clock from
* a 25MHz crystal using both PLL and PLL2.
@@ -294,6 +321,13 @@
/* Derived constants and error checks. */
/*===========================================================================*/
+/* PLL2 usage check.*/
+#if STM32_ACTIVATE_PLL2 && \
+ (STM32_PREDIV1SRC != STM32_PREDIV1SRC_PLL2) && \
+ (STM32_MCO != STM32_MCO_PLL2)
+#error "PLL2 activated but not used"
+#endif
+
/**
* @brief PREDIV1 field.
*/
@@ -338,9 +372,22 @@
#error "invalid STM32_PLL2MUL_VALUE value specified"
#endif
-/* The following values are only used if PLL2 clock is selected as source
- for the PLL clock */
-#if (STM32_PREDIV1SRC == STM32_PREDIV1SRC_PLL2) || defined(__DOXYGEN__)
+/**
+ * @brief PLL3MUL field.
+ */
+#if ((STM32_PLL3MUL_VALUE >= 8) && (STM32_PLL3MUL_VALUE <= 14)) || \
+ defined(__DOXYGEN__)
+#define STM32_PLL3MUL ((STM32_PLL3MUL_VALUE - 2) << 12)
+#elif (STM32_PLL3MUL_VALUE == 16)
+#define STM32_PLL3MUL (14 << 12)
+#elif (STM32_PLL3MUL_VALUE == 20)
+#define STM32_PLL3MUL (15 << 12)
+#else
+#error "invalid STM32_PLL3MUL_VALUE value specified"
+#endif
+
+/* The following values are only used if PLL2 is activated */
+#if STM32_ACTIVATE_PLL2
/**
* @brief PLL2 input frequency.
*/
@@ -356,16 +403,54 @@
*/
#define STM32_PLL2CLKOUT (STM32_PLL2CLKIN * STM32_PLL2MUL_VALUE)
+/**
+ * @brief PLL2 VCO clock frequency.
+ */
+#define STM32_PLL2VCO (STM32_PLL2CLKOUT * 2)
+
/* PLL2 output frequency range check.*/
-#if (STM32_PLL2CLKOUT < 40000000) || (STM32_PLL2CLKOUT > 74000000)
-#error "STM32_PLL2CLKOUT outside acceptable range (40...74MHz)"
+#if (STM32_PLL2VCO < 80000000) || (STM32_PLL2VCO > 148000000)
+#error "STM32_PLL2VCO outside acceptable range (80...148MHz)"
+#endif
+#endif /* STM32_ACTIVATE_PLL2 */
+
+/* The following values are only used if PLL3 is activated */
+#if STM32_ACTIVATE_PLL3
+/**
+ * @brief PLL3 input frequency.
+ */
+#define STM32_PLL3CLKIN (STM32_HSECLK / STM32_PREDIV2_VALUE)
+
+/* PLL3 input frequency range check.*/
+#if (STM32_PLL3CLKIN < 3000000) || (STM32_PLL3CLKIN > 5000000)
+#error "STM32_PLL3CLKIN outside acceptable range (3...5MHz)"
#endif
-#endif /* STM32_PREDIV1SRC == STM32_PREDIV1SRC_PLL2 */
/**
+ * @brief PLL3 output clock frequency.
+ */
+#define STM32_PLL3CLKOUT (STM32_PLL3CLKIN * STM32_PLL3MUL_VALUE)
+
+/**
+ * @brief PLL3 VCO clock frequency.
+ */
+#define STM32_PLL3VCO (STM32_PLL3CLKOUT * 2)
+
+/* PLL3 output frequency range check.*/
+#if (STM32_PLL3VCO < 80000000) || (STM32_PLL3VCO > 148000000)
+#error "STM32_PLL3CLKOUT outside acceptable range (80...148MHz)"
+#endif
+#endif /* STM32_ACTIVATE_PLL3 */
+
+/* The following values are only used if PLL1 is activated */
+#if STM32_ACTIVATE_PLL1
+/**
* @brief PREDIV1 input frequency.
*/
#if (STM32_PREDIV1SRC == STM32_PREDIV1SRC_PLL2) || defined(__DOXYGEN__)
+#if !STM32_ACTIVATE_PLL2
+#error "PLL2 selected as clock source for STM32_PREDIV1SRC but not activated"
+#endif
#define STM32_PREDIV1CLK STM32_PLL2CLKOUT
#elif STM32_PREDIV1SRC == STM32_PREDIV1SRC_HSE
#define STM32_PREDIV1CLK STM32_HSECLK
@@ -377,9 +462,9 @@
* @brief PLL input clock frequency.
*/
#if (STM32_PLLSRC == STM32_PLLSRC_PREDIV1) || defined(__DOXYGEN__)
-#define STM32_PLLCLKIN (STM32_PREDIV1CLK / STM32_PREDIV1_VALUE)
+#define STM32_PLLCLKIN (STM32_PREDIV1CLK / STM32_PREDIV1_VALUE)
#elif STM32_PLLSRC == STM32_PLLSRC_HSI
-#define STM32_PLLCLKIN (STM32_HSICLK / 2)
+#define STM32_PLLCLKIN (STM32_HSICLK / 2)
#else
#error "invalid STM32_PLLSRC value specified"
#endif
@@ -392,17 +477,26 @@
/**
* @brief PLL output clock frequency.
*/
-#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
+#define STM32_PLLCLKOUT (STM32_PLLCLKIN * STM32_PLLMUL_VALUE)
+
+/**
+ * @brief PLL VCO clock frequency.
+ */
+#define STM32_PLLVCO (STM32_PLLCLKOUT * 2)
/* PLL output frequency range check.*/
-#if (STM32_PLLCLKOUT < 18000000) || (STM32_PLLCLKOUT > 72000000)
-#error "STM32_PLLCLKOUT outside acceptable range (18...72MHz)"
+#if (STM32_PLLVCO < 36000000) || (STM32_PLLVCO > 144000000)
+#error "STM32_PLLVCO outside acceptable range (36...144MHz)"
#endif
+#endif /* STM32_ACTIVATE_PLL1 */
/**
* @brief System clock source.
*/
#if (STM32_SW == STM32_SW_PLL) || defined(__DOXYGEN__)
+#if !STM32_ACTIVATE_PLL1
+#error "PLL1 selected as clock source for STM32_SYSCLK but not activated"
+#endif
#define STM32_SYSCLK STM32_PLLCLKOUT
#elif (STM32_SW == STM32_SW_HSI)
#define STM32_SYSCLK STM32_HSICLK
@@ -515,9 +609,9 @@
* @brief OTG frequency.
*/
#if (STM32_OTGFSPRE == STM32_OTGFSPRE_DIV3) || defined(__DOXYGEN__)
-#define STM32_OTGFSCLK ((STM32_PLLCLKOUT * 2) / 3)
+#define STM32_OTGFSCLK (STM32_PLLVCO / 3)
#elif (STM32_OTGFSPRE == STM32_OTGFSPRE_DIV2)
-#define STM32_OTGFSCLK STM32_PLLCLKOUT
+#define STM32_OTGFSCLK (STM32_PLLVCO / 2)
#else
#error "invalid STM32_OTGFSPRE value specified"
#endif
diff --git a/os/hal/platforms/STM32/icu_lld.c b/os/hal/platforms/STM32/icu_lld.c
new file mode 100644
index 000000000..ae3287ef9
--- /dev/null
+++ b/os/hal/platforms/STM32/icu_lld.c
@@ -0,0 +1,425 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/icu_lld.c
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/**
+ * @brief ICUD1 driver identifier.
+ * @note The driver ICUD1 allocates the complex timer TIM1 when enabled.
+ */
+#if STM32_ICU_USE_TIM1 || defined(__DOXYGEN__)
+ICUDriver ICUD1;
+#endif
+
+/**
+ * @brief ICUD2 driver identifier.
+ * @note The driver ICUD1 allocates the timer TIM2 when enabled.
+ */
+#if STM32_ICU_USE_TIM2 || defined(__DOXYGEN__)
+ICUDriver ICUD2;
+#endif
+
+/**
+ * @brief ICUD3 driver identifier.
+ * @note The driver ICUD1 allocates the timer TIM3 when enabled.
+ */
+#if STM32_ICU_USE_TIM3 || defined(__DOXYGEN__)
+ICUDriver ICUD3;
+#endif
+
+/**
+ * @brief ICUD4 driver identifier.
+ * @note The driver ICUD4 allocates the timer TIM4 when enabled.
+ */
+#if STM32_ICU_USE_TIM4 || defined(__DOXYGEN__)
+ICUDriver ICUD4;
+#endif
+
+/**
+ * @brief ICUD5 driver identifier.
+ * @note The driver ICUD5 allocates the timer TIM5 when enabled.
+ */
+#if STM32_ICU_USE_TIM5 || defined(__DOXYGEN__)
+ICUDriver ICUD5;
+#endif
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Shared IRQ handler.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ */
+static void icu_lld_serve_interrupt(ICUDriver *icup) {
+ uint16_t sr;
+
+ sr = icup->tim->SR & icup->tim->DIER;
+ icup->tim->SR = 0;
+ if ((sr & TIM_SR_CC1IF) != 0)
+ _icu_isr_invoke_period_cb(icup);
+ if ((sr & TIM_SR_CC2IF) != 0)
+ _icu_isr_invoke_width_cb(icup);
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1
+/**
+ * @brief TIM1 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM1_CC_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD1);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM1 */
+
+#if STM32_ICU_USE_TIM2
+/**
+ * @brief TIM2 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM2_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD2);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM2 */
+
+#if STM32_ICU_USE_TIM3
+/**
+ * @brief TIM3 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM3_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD3);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM3 */
+
+#if STM32_ICU_USE_TIM4
+/**
+ * @brief TIM4 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM4_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD4);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM4 */
+
+#if STM32_ICU_USE_TIM5
+/**
+ * @brief TIM5 compare interrupt handler.
+ * @note It is assumed that the various sources are only activated if the
+ * associated callback pointer is not equal to @p NULL in order to not
+ * perform an extra check in a potentially critical interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(TIM5_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ icu_lld_serve_interrupt(&ICUD5);
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* STM32_ICU_USE_TIM5 */
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level ICU driver initialization.
+ *
+ * @notapi
+ */
+void icu_lld_init(void) {
+
+#if STM32_ICU_USE_TIM1
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD1);
+ ICUD1.tim = TIM1;
+#endif
+
+#if STM32_ICU_USE_TIM2
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD2);
+ ICUD2.tim = TIM2;
+#endif
+
+#if STM32_ICU_USE_TIM3
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD3);
+ ICUD3.tim = TIM3;
+#endif
+
+#if STM32_ICU_USE_TIM4
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD4);
+ ICUD4.tim = TIM4;
+#endif
+
+#if STM32_ICU_USE_TIM5
+ /* Driver initialization.*/
+ icuObjectInit(&ICUD5);
+ ICUD5.tim = TIM5;
+#endif
+}
+
+/**
+ * @brief Configures and activates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_start(ICUDriver *icup) {
+ uint32_t clock, psc;
+
+ if (icup->state == ICU_STOP) {
+ /* Clock activation and timer reset.*/
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+ RCC->APB2ENR |= RCC_APB2ENR_TIM1EN;
+ RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
+ RCC->APB2RSTR = 0;
+ NVICEnableVector(TIM1_CC_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM1_IRQ_PRIORITY));
+ clock = STM32_TIMCLK2;
+ }
+#endif
+#if STM32_ICU_USE_TIM2
+ if (&ICUD2 == icup) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM2_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM2_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
+ }
+#endif
+#if STM32_ICU_USE_TIM3
+ if (&ICUD3 == icup) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM3_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM3_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
+ }
+#endif
+#if STM32_ICU_USE_TIM4
+ if (&ICUD4 == icup) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM4EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM4_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM4_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
+ }
+#endif
+
+#if STM32_ICU_USE_TIM5
+ if (&ICUD5 == icup) {
+ RCC->APB1ENR |= RCC_APB1ENR_TIM5EN;
+ RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
+ RCC->APB1RSTR = 0;
+ NVICEnableVector(TIM5_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_ICU_TIM5_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
+ }
+#endif
+ }
+ else {
+ /* Driver re-configuration scenario, it must be stopped first.*/
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->DIER = 0; /* All IRQs disabled. */
+ icup->tim->SR = 0; /* Clear eventual pending IRQs. */
+ icup->tim->CCR1 = 0; /* Comparator 1 disabled. */
+ icup->tim->CCR2 = 0; /* Comparator 2 disabled. */
+ icup->tim->CNT = 0; /* Counter reset to zero. */
+ }
+
+ /* Timer configuration.*/
+ psc = (clock / icup->config->frequency) - 1;
+ chDbgAssert((psc <= 0xFFFF) &&
+ ((psc + 1) * icup->config->frequency) == clock,
+ "icu_lld_start(), #1", "invalid frequency");
+ icup->tim->PSC = (uint16_t)psc;
+ icup->tim->ARR = 0xFFFF;
+
+ /* CCMR1_CC1S = 01 = CH1 Input on TI1.
+ CCMR1_CC2S = 10 = CH2 Input on TI2.*/
+ icup->tim->CCMR1 = TIM_CCMR1_CC1S_0 |
+ TIM_CCMR1_CC2S_1;
+ /* SMCR_TS = 101, input is TI1FP1.
+ SMCR_SMS = 100, reset on rising edge.*/
+ icup->tim->SMCR = TIM_SMCR_TS_2 | TIM_SMCR_TS_0 |
+ TIM_SMCR_SMS_2;
+ /* The CCER settings depend on the selected trigger mode.
+ ICU_INPUT_ACTIVE_HIGH: Active on rising edge, idle on falling edge.
+ ICU_INPUT_ACTIVE_LOW: Active on falling edge, idle on rising edge.*/
+ if (icup->config->mode == ICU_INPUT_ACTIVE_HIGH)
+ icup->tim->CCER = TIM_CCER_CC1E |
+ TIM_CCER_CC2E | TIM_CCER_CC2P;
+ else
+ icup->tim->CCER = TIM_CCER_CC1E | TIM_CCER_CC1P |
+ TIM_CCER_CC2E;
+}
+
+/**
+ * @brief Deactivates the ICU peripheral.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_stop(ICUDriver *icup) {
+
+ if (icup->state == ICU_READY) {
+ /* Clock deactivation.*/
+ icup->tim->CR1 = 0; /* Timer disabled. */
+ icup->tim->DIER = 0; /* All IRQs disabled. */
+ icup->tim->SR = 0; /* Clear eventual pending IRQs. */
+
+#if STM32_ICU_USE_TIM1
+ if (&ICUD1 == icup) {
+ NVICDisableVector(TIM1_CC_IRQn);
+ RCC->APB2ENR &= ~RCC_APB2ENR_TIM1EN;
+ }
+#endif
+ }
+#if STM32_ICU_USE_TIM2
+ if (&ICUD2 == icup) {
+ NVICDisableVector(TIM2_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM2EN;
+ }
+#endif
+#if STM32_ICU_USE_TIM3
+ if (&ICUD3 == icup) {
+ NVICDisableVector(TIM3_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM3EN;
+ }
+#endif
+#if STM32_ICU_USE_TIM4
+ if (&ICUD4 == icup) {
+ NVICDisableVector(TIM4_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM4EN;
+ }
+#endif
+#if STM32_ICU_USE_TIM5
+ if (&ICUD5 == icup) {
+ NVICDisableVector(TIM5_IRQn);
+ RCC->APB1ENR &= ~RCC_APB1ENR_TIM5EN;
+ }
+#endif
+}
+
+/**
+ * @brief Enables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_enable(ICUDriver *icup) {
+
+ icup->tim->SR = 0; /* Clear pending IRQs (if any). */
+ if (icup->config->period_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC1IE;
+ if (icup->config->width_cb != NULL)
+ icup->tim->DIER |= TIM_DIER_CC2IE;
+ icup->tim->CR1 = TIM_CR1_URS | TIM_CR1_CEN;
+}
+
+/**
+ * @brief Disables the input capture.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ *
+ * @notapi
+ */
+void icu_lld_disable(ICUDriver *icup) {
+
+ icup->tim->CR1 = 0; /* Initially stopped. */
+ icup->tim->SR = 0; /* Clear pending IRQs (if any). */
+ icup->tim->DIER = 0; /* Interrupts disabled. */
+}
+
+#endif /* HAL_USE_ICU */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/icu_lld.h b/os/hal/platforms/STM32/icu_lld.h
new file mode 100644
index 000000000..b98b8bf86
--- /dev/null
+++ b/os/hal/platforms/STM32/icu_lld.h
@@ -0,0 +1,290 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/icu_lld.h
+ * @brief STM32 ICU subsystem low level driver header.
+ *
+ * @addtogroup ICU
+ * @{
+ */
+
+#ifndef _ICU_LLD_H_
+#define _ICU_LLD_H_
+
+#if HAL_USE_ICU || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver constants. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* Driver pre-compile time settings. */
+/*===========================================================================*/
+
+/**
+ * @brief ICUD1 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD1 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM1) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM1 TRUE
+#endif
+
+/**
+ * @brief ICUD2 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD2 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM2) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM2 TRUE
+#endif
+
+/**
+ * @brief ICUD3 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD3 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM3) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM3 TRUE
+#endif
+
+/**
+ * @brief ICUD4 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD4 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM4) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM4 TRUE
+#endif
+
+/**
+ * @brief ICUD5 driver enable switch.
+ * @details If set to @p TRUE the support for ICUD5 is included.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_ICU_USE_TIM5) || defined(__DOXYGEN__)
+#define STM32_ICU_USE_TIM5 TRUE
+#endif
+
+/**
+ * @brief ICUD1 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM1_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD2 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM2_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD3 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM3_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD4 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM4_IRQ_PRIORITY 7
+#endif
+
+/**
+ * @brief ICUD5 interrupt priority level setting.
+ */
+#if !defined(STM32_ICU_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_ICU_TIM5_IRQ_PRIORITY 7
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 && !STM32_HAS_TIM1
+#error "TIM1 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM2 && !STM32_HAS_TIM2
+#error "TIM2 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM3 && !STM32_HAS_TIM3
+#error "TIM3 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM4 && !STM32_HAS_TIM4
+#error "TIM4 not present in the selected device"
+#endif
+
+#if STM32_ICU_USE_TIM5 && !STM32_HAS_TIM5
+#error "TIM5 not present in the selected device"
+#endif
+
+#if !STM32_ICU_USE_TIM1 && !STM32_ICU_USE_TIM2 && \
+ !STM32_ICU_USE_TIM3 && !STM32_ICU_USE_TIM4 && \
+ !STM32_ICU_USE_TIM5
+#error "ICU driver activated but no TIM peripheral assigned"
+#endif
+
+/*===========================================================================*/
+/* Driver data structures and types. */
+/*===========================================================================*/
+
+/**
+ * @brief ICU driver mode.
+ */
+typedef enum {
+ ICU_INPUT_ACTIVE_HIGH = 0, /**< Trigger on rising edge. */
+ ICU_INPUT_ACTIVE_LOW = 1, /**< Trigger on falling edge. */
+} icumode_t;
+
+/**
+ * @brief ICU frequency type.
+ */
+typedef uint32_t icufreq_t;
+
+/**
+ * @brief ICU counter type.
+ */
+typedef uint16_t icucnt_t;
+
+/**
+ * @brief Driver configuration structure.
+ * @note It could be empty on some architectures.
+ */
+typedef struct {
+ /**
+ * @brief Driver mode.
+ */
+ icumode_t mode;
+ /**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ icufreq_t frequency;
+ /**
+ * @brief Callback for pulse width measurement.
+ */
+ icucallback_t width_cb;
+ /**
+ * @brief Callback for cycle period measurement.
+ */
+ icucallback_t period_cb;
+ /* End of the mandatory fields.*/
+} ICUConfig;
+
+/**
+ * @brief Structure representing an ICU driver.
+ */
+struct ICUDriver {
+ /**
+ * @brief Driver state.
+ */
+ icustate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const ICUConfig *config;
+#if defined(ICU_DRIVER_EXT_FIELDS)
+ ICU_DRIVER_EXT_FIELDS
+#endif
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the TIMx registers block.
+ */
+ TIM_TypeDef *tim;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/**
+ * @brief Returns the width of the latest pulse.
+ * @details The pulse width is defined as number of ticks between the start
+ * edge and the stop edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_width(icup) ((icup)->tim->CCR2 + 1)
+
+/**
+ * @brief Returns the width of the latest cycle.
+ * @details The cycle width is defined as number of ticks between a start
+ * edge and the next start edge.
+ *
+ * @param[in] icup pointer to the @p ICUDriver object
+ * @return The number of ticks.
+ *
+ * @notapi
+ */
+#define icu_lld_get_period(icup) ((icup)->tim->CCR1 + 1)
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if STM32_ICU_USE_TIM1 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD1;
+#endif
+
+#if STM32_ICU_USE_TIM2 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD2;
+#endif
+
+#if STM32_ICU_USE_TIM3 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD3;
+#endif
+
+#if STM32_ICU_USE_TIM4 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD4;
+#endif
+
+#if STM32_ICU_USE_TIM5 && !defined(__DOXYGEN__)
+extern ICUDriver ICUD5;
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void icu_lld_init(void);
+ void icu_lld_start(ICUDriver *icup);
+ void icu_lld_stop(ICUDriver *icup);
+ void icu_lld_enable(ICUDriver *icup);
+ void icu_lld_disable(ICUDriver *icup);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* HAL_USE_ICU */
+
+#endif /* _ICU_LLD_H_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/pal_lld.c b/os/hal/platforms/STM32/pal_lld.c
index ac90883f7..c56996db7 100644
--- a/os/hal/platforms/STM32/pal_lld.c
+++ b/os/hal/platforms/STM32/pal_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -31,25 +32,15 @@
#if HAL_USE_PAL || defined(__DOXYGEN__)
#if STM32_HAS_GPIOG
-#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
- RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
- RCC_APB2RSTR_IOPERST | RCC_APB2RSTR_IOPFRST | \
- RCC_APB2RSTR_IOPGRST | RCC_APB2RSTR_AFIORST);
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
RCC_APB2ENR_IOPEEN | RCC_APB2ENR_IOPFEN | \
RCC_APB2ENR_IOPGEN | RCC_APB2ENR_AFIOEN)
#elif STM32_HAS_GPIOE
-#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
- RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
- RCC_APB2RSTR_IOPERST | RCC_APB2RSTR_AFIORST);
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
RCC_APB2ENR_IOPEEN | RCC_APB2ENR_AFIOEN)
#else
-#define APB2_RST_MASK (RCC_APB2RSTR_IOPARST | RCC_APB2RSTR_IOPBRST | \
- RCC_APB2RSTR_IOPCRST | RCC_APB2RSTR_IOPDRST | \
- RCC_APB2RSTR_AFIORST)
#define APB2_EN_MASK (RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN | \
RCC_APB2ENR_IOPCEN | RCC_APB2ENR_IOPDEN | \
RCC_APB2ENR_AFIOEN)
@@ -91,11 +82,8 @@ void _pal_lld_init(const PALConfig *config) {
RCC->APB2ENR |= APB2_EN_MASK;
/*
- * Resets the GPIO ports and AFIO.
+ * Initial GPIO setup.
*/
- RCC->APB2RSTR = APB2_RST_MASK;
- RCC->APB2RSTR = 0;
-
GPIOA->ODR = config->PAData.odr;
GPIOA->CRH = config->PAData.crh;
GPIOA->CRL = config->PAData.crl;
diff --git a/os/hal/platforms/STM32/pal_lld.h b/os/hal/platforms/STM32/pal_lld.h
index a6d1236ae..2919c91f6 100644
--- a/os/hal/platforms/STM32/pal_lld.h
+++ b/os/hal/platforms/STM32/pal_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -278,10 +279,9 @@ typedef GPIO_TypeDef * ioportid_t;
*
* @notapi
*/
-#define pal_lld_writegroup(port, mask, offset, bits) { \
- (port)->BSRR = ((~(bits) & (mask)) << (16 + (offset))) | \
- (((bits) & (mask)) << (offset)); \
-}
+#define pal_lld_writegroup(port, mask, offset, bits) \
+ ((port)->BSRR = ((~(bits) & (mask)) << (16 + (offset))) | \
+ (((bits) & (mask)) << (offset)))
/**
* @brief Pads group mode setup.
diff --git a/os/hal/platforms/STM32/platform.dox b/os/hal/platforms/STM32/platform.dox
index 91f0addca..50ab84f38 100644
--- a/os/hal/platforms/STM32/platform.dox
+++ b/os/hal/platforms/STM32/platform.dox
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -61,7 +62,7 @@
* - Programmable ADC interrupt priority level.
* - Programmable DMA bus priority for each DMA channel.
* - Programmable DMA interrupt priority for each DMA channel.
- * - Programmable DMA error hook for each DMA channel.
+ * - Programmable DMA error hook.
* .
* @ingroup STM32_DRIVERS
*/
@@ -100,7 +101,45 @@
*/
/**
- * @defgroup STM32_PAL STM32 GPIO Support
+ * @defgroup STM32_GPT STM32 GPT Support
+ * @details The STM32 GPT driver uses the TIMx peripherals.
+ *
+ * @section stm32_gpt_1 Supported HW resources
+ * - TIM1.
+ * - TIM2.
+ * - TIM3.
+ * - TIM4.
+ * - TIM5.
+ * .
+ * @section stm32_gpt_2 STM32 GPT driver implementation features
+ * - Each timer can be independently enabled and programmed. Unused
+ * peripherals are left in low power mode.
+ * - Programmable TIMx interrupts priority level.
+ * .
+ * @ingroup STM32_DRIVERS
+ */
+
+/**
+ * @defgroup STM32_ICU STM32 ICU Support
+ * @details The STM32 ICU driver uses the TIMx peripherals.
+ *
+ * @section stm32_icu_1 Supported HW resources
+ * - TIM1.
+ * - TIM2.
+ * - TIM3.
+ * - TIM4.
+ * - TIM5.
+ * .
+ * @section stm32_icu_2 STM32 ICU driver implementation features
+ * - Each timer can be independently enabled and programmed. Unused
+ * peripherals are left in low power mode.
+ * - Programmable TIMx interrupts priority level.
+ * .
+ * @ingroup STM32_DRIVERS
+ */
+
+/**
+ * @defgroup STM32_PAL STM32 PAL Support
* @details The STM32 PAL driver uses the GPIO peripherals.
*
* @section stm32_pal_1 Supported HW resources
@@ -158,6 +197,7 @@
* - TIM2.
* - TIM3.
* - TIM4.
+ * - TIM5.
* .
* @section stm32_pwm_2 STM32 PWM driver implementation features
* - Each timer can be independently enabled and programmed. Unused
@@ -169,32 +209,24 @@
*/
/**
- * @defgroup STM32_SPI STM32 SPI Support
- * @details The SPI driver supports the STM32 SPI peripherals using DMA
- * channels for maximum performance.
+ * @defgroup STM32_SDC STM32 SDC Support
+ * @details The STM32 SDC driver uses the SDIO peripheral.
*
- * @section stm32_spi_1 Supported HW resources
- * - SPI1.
- * - SPI2.
- * - SPI3 (where present).
- * - DMA1.
- * - DMA2 (where present).
+ * @section stm32_sdc_1 Supported HW resources
+ * - SDIO.
+ * - DMA2.
* .
- * @section stm32_spi_2 STM32 SPI driver implementation features
+ * @section stm32_sdc_2 STM32 SDC driver implementation features
* - Clock stop for reduced power usage when the driver is in stop state.
- * - Each SPI can be independently enabled and programmed. Unused
- * peripherals are left in low power mode.
- * - Programmable interrupt priority levels for each SPI.
+ * - Programmable interrupt priority.
* - DMA is used for receiving and transmitting.
* - Programmable DMA bus priority for each DMA channel.
- * - Programmable DMA interrupt priority for each DMA channel.
- * - Programmable DMA error hook for each DMA channel.
* .
* @ingroup STM32_DRIVERS
*/
/**
- * @defgroup STM32_SERIAL STM32 USART Support (buffered)
+ * @defgroup STM32_SERIAL STM32 Serial Support
* @details The STM32 Serial driver uses the USART/UART peripherals in a
* buffered, interrupt driven, implementation.
*
@@ -217,7 +249,32 @@
*/
/**
- * @defgroup STM32_UART STM32 USART Support (unbuffered)
+ * @defgroup STM32_SPI STM32 SPI Support
+ * @details The SPI driver supports the STM32 SPI peripherals using DMA
+ * channels for maximum performance.
+ *
+ * @section stm32_spi_1 Supported HW resources
+ * - SPI1.
+ * - SPI2.
+ * - SPI3 (where present).
+ * - DMA1.
+ * - DMA2 (where present).
+ * .
+ * @section stm32_spi_2 STM32 SPI driver implementation features
+ * - Clock stop for reduced power usage when the driver is in stop state.
+ * - Each SPI can be independently enabled and programmed. Unused
+ * peripherals are left in low power mode.
+ * - Programmable interrupt priority levels for each SPI.
+ * - DMA is used for receiving and transmitting.
+ * - Programmable DMA bus priority for each DMA channel.
+ * - Programmable DMA interrupt priority for each DMA channel.
+ * - Programmable DMA error hook.
+ * .
+ * @ingroup STM32_DRIVERS
+ */
+
+/**
+ * @defgroup STM32_UART STM32 UART Support
* @details The UART driver supports the STM32 USART peripherals using DMA
* channels for maximum performance.
*
@@ -226,6 +283,7 @@
* - USART1.
* - USART2.
* - USART3 (where present).
+ * - UART4 (where present).
* - DMA1.
* - DMA2 (where present).
* .
@@ -237,7 +295,23 @@
* - DMA is used for receiving and transmitting.
* - Programmable DMA bus priority for each DMA channel.
* - Programmable DMA interrupt priority for each DMA channel.
- * - Programmable DMA error hook for each DMA channel.
+ * - Programmable DMA error hook.
+ * .
+ * @ingroup STM32_DRIVERS
+ */
+
+/**
+ * @defgroup STM32_USB STM32 USB Support
+ * @details The USB driver supports the STM32 USB peripheral.
+ *
+ * @section stm32_usb_1 Supported HW resources
+ * The USB driver can support any of the following hardware resources:
+ * - USB.
+ * .
+ * @section stm32_usb_2 STM32 USB driver implementation features
+ * - Clock stop for reduced power usage when the driver is in stop state.
+ * - Programmable interrupt priority levels.
+ * - Each endpoint programmable in Control, Bulk and Interrupt modes.
* .
* @ingroup STM32_DRIVERS
*/
diff --git a/os/hal/platforms/STM32/platform.mk b/os/hal/platforms/STM32/platform.mk
index 35717687f..02f090e5e 100644
--- a/os/hal/platforms/STM32/platform.mk
+++ b/os/hal/platforms/STM32/platform.mk
@@ -2,8 +2,11 @@
PLATFORMSRC = ${CHIBIOS}/os/hal/platforms/STM32/hal_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/adc_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/can_lld.c \
+ ${CHIBIOS}/os/hal/platforms/STM32/gpt_lld.c \
+ ${CHIBIOS}/os/hal/platforms/STM32/icu_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/pal_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/pwm_lld.c \
+ ${CHIBIOS}/os/hal/platforms/STM32/sdc_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/serial_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/spi_lld.c \
${CHIBIOS}/os/hal/platforms/STM32/uart_lld.c \
diff --git a/os/hal/platforms/STM32/pwm_lld.c b/os/hal/platforms/STM32/pwm_lld.c
index f78896e95..bb6dad8f2 100644
--- a/os/hal/platforms/STM32/pwm_lld.c
+++ b/os/hal/platforms/STM32/pwm_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -47,40 +48,40 @@
/*===========================================================================*/
/**
- * @brief PWM1 driver identifier.
- * @note The driver PWM1 allocates the complex timer TIM1 when enabled.
+ * @brief PWMD1 driver identifier.
+ * @note The driver PWMD1 allocates the complex timer TIM1 when enabled.
*/
#if STM32_PWM_USE_TIM1 || defined(__DOXYGEN__)
PWMDriver PWMD1;
#endif
/**
- * @brief PWM2 driver identifier.
- * @note The driver PWM2 allocates the timer TIM2 when enabled.
+ * @brief PWMD2 driver identifier.
+ * @note The driver PWMD2 allocates the timer TIM2 when enabled.
*/
#if STM32_PWM_USE_TIM2 || defined(__DOXYGEN__)
PWMDriver PWMD2;
#endif
/**
- * @brief PWM3 driver identifier.
- * @note The driver PWM3 allocates the timer TIM3 when enabled.
+ * @brief PWMD3 driver identifier.
+ * @note The driver PWMD3 allocates the timer TIM3 when enabled.
*/
#if STM32_PWM_USE_TIM3 || defined(__DOXYGEN__)
PWMDriver PWMD3;
#endif
/**
- * @brief PWM4 driver identifier.
- * @note The driver PWM4 allocates the timer TIM4 when enabled.
+ * @brief PWMD4 driver identifier.
+ * @note The driver PWMD4 allocates the timer TIM4 when enabled.
*/
#if STM32_PWM_USE_TIM4 || defined(__DOXYGEN__)
PWMDriver PWMD4;
#endif
/**
- * @brief PWM5 driver identifier.
- * @note The driver PWM5 allocates the timer TIM5 when enabled.
+ * @brief PWMD5 driver identifier.
+ * @note The driver PWMD5 allocates the timer TIM5 when enabled.
*/
#if STM32_PWM_USE_TIM5 || defined(__DOXYGEN__)
PWMDriver PWMD5;
@@ -101,24 +102,26 @@ PWMDriver PWMD5;
* @note It is assumed that the various sources are only activated if the
* associated callback pointer is not equal to @p NULL in order to not
* perform an extra check in a potentially critical interrupt handler.
+ *
+ * @param[in] pwmp pointer to a @p PWMDriver object
*/
static void serve_interrupt(PWMDriver *pwmp) {
uint16_t sr;
- sr = pwmp->pd_tim->SR;
- sr &= pwmp->pd_tim->DIER;
- pwmp->pd_tim->SR = ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF |
- TIM_SR_CC4IF | TIM_SR_UIF);
+ sr = pwmp->tim->SR;
+ sr &= pwmp->tim->DIER;
+ pwmp->tim->SR = ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF |
+ TIM_SR_CC4IF | TIM_SR_UIF);
if ((sr & TIM_SR_CC1IF) != 0)
- pwmp->pd_config->pc_channels[0].pcc_callback(pwmp);
+ pwmp->config->channels[0].callback(pwmp);
if ((sr & TIM_SR_CC2IF) != 0)
- pwmp->pd_config->pc_channels[1].pcc_callback(pwmp);
+ pwmp->config->channels[1].callback(pwmp);
if ((sr & TIM_SR_CC3IF) != 0)
- pwmp->pd_config->pc_channels[2].pcc_callback(pwmp);
+ pwmp->config->channels[2].callback(pwmp);
if ((sr & TIM_SR_CC4IF) != 0)
- pwmp->pd_config->pc_channels[3].pcc_callback(pwmp);
+ pwmp->config->channels[3].callback(pwmp);
if ((sr & TIM_SR_UIF) != 0)
- pwmp->pd_config->pc_callback(pwmp);
+ pwmp->config->callback(pwmp);
}
#endif /* STM32_PWM_USE_TIM2 || ... || STM32_PWM_USE_TIM5 */
@@ -140,7 +143,7 @@ CH_IRQ_HANDLER(TIM1_UP_IRQHandler) {
CH_IRQ_PROLOGUE();
TIM1->SR = ~TIM_SR_UIF;
- PWMD1.pd_config->pc_callback(&PWMD1);
+ PWMD1.config->callback(&PWMD1);
CH_IRQ_EPILOGUE();
}
@@ -161,13 +164,13 @@ CH_IRQ_HANDLER(TIM1_CC_IRQHandler) {
sr = TIM1->SR & TIM1->DIER;
TIM1->SR = ~(TIM_SR_CC1IF | TIM_SR_CC2IF | TIM_SR_CC3IF | TIM_SR_CC4IF);
if ((sr & TIM_SR_CC1IF) != 0)
- PWMD1.pd_config->pc_channels[0].pcc_callback(&PWMD1);
+ PWMD1.config->channels[0].callback(&PWMD1);
if ((sr & TIM_SR_CC2IF) != 0)
- PWMD1.pd_config->pc_channels[1].pcc_callback(&PWMD1);
+ PWMD1.config->channels[1].callback(&PWMD1);
if ((sr & TIM_SR_CC3IF) != 0)
- PWMD1.pd_config->pc_channels[2].pcc_callback(&PWMD1);
+ PWMD1.config->channels[2].callback(&PWMD1);
if ((sr & TIM_SR_CC4IF) != 0)
- PWMD1.pd_config->pc_channels[3].pcc_callback(&PWMD1);
+ PWMD1.config->channels[3].callback(&PWMD1);
CH_IRQ_EPILOGUE();
}
@@ -249,75 +252,50 @@ CH_IRQ_HANDLER(TIM5_IRQHandler) {
void pwm_lld_init(void) {
#if STM32_PWM_USE_TIM1
- /* TIM1 reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB2RSTR = RCC_APB2RSTR_TIM1RST;
- RCC->APB2RSTR = 0;
-
/* Driver initialization.*/
pwmObjectInit(&PWMD1);
- PWMD1.pd_enabled_channels = 0;
- PWMD1.pd_tim = TIM1;
+ PWMD1.tim = TIM1;
#endif
#if STM32_PWM_USE_TIM2
- /* TIM2 reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_TIM2RST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
pwmObjectInit(&PWMD2);
- PWMD2.pd_enabled_channels = 0;
- PWMD2.pd_tim = TIM2;
+ PWMD2.tim = TIM2;
#endif
#if STM32_PWM_USE_TIM3
- /* TIM2 reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_TIM3RST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
pwmObjectInit(&PWMD3);
- PWMD3.pd_enabled_channels = 0;
- PWMD3.pd_tim = TIM3;
+ PWMD3.tim = TIM3;
#endif
#if STM32_PWM_USE_TIM4
- /* TIM2 reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_TIM4RST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
pwmObjectInit(&PWMD4);
- PWMD4.pd_enabled_channels = 0;
- PWMD4.pd_tim = TIM4;
+ PWMD4.tim = TIM4;
#endif
#if STM32_PWM_USE_TIM5
- /* TIM2 reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_TIM5RST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
pwmObjectInit(&PWMD5);
- PWMD5.pd_enabled_channels = 0;
- PWMD5.pd_tim = TIM5;
+ PWMD5.tim = TIM5;
#endif
}
/**
* @brief Configures and activates the PWM peripheral.
+ * @note Starting a driver that is already in the @p PWM_READY state
+ * disables all the active channels.
*
* @param[in] pwmp pointer to a @p PWMDriver object
*
* @notapi
*/
void pwm_lld_start(PWMDriver *pwmp) {
+ uint32_t clock, psc;
uint16_t ccer;
- /* Reset channels.*/
- pwmp->pd_enabled_channels = 0; /* All channels disabled. */
-
- if (pwmp->pd_state == PWM_STOP) {
+ if (pwmp->state == PWM_STOP) {
/* Clock activation and timer reset.*/
#if STM32_PWM_USE_TIM1
if (&PWMD1 == pwmp) {
@@ -328,6 +306,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
NVICEnableVector(TIM1_CC_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM1_IRQ_PRIORITY));
+ clock = STM32_TIMCLK2;
}
#endif
#if STM32_PWM_USE_TIM2
@@ -337,6 +316,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
RCC->APB1RSTR = 0;
NVICEnableVector(TIM2_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM2_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM3
@@ -346,6 +326,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
RCC->APB1RSTR = 0;
NVICEnableVector(TIM3_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM3_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
}
#endif
#if STM32_PWM_USE_TIM4
@@ -355,6 +336,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
RCC->APB1RSTR = 0;
NVICEnableVector(TIM4_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM4_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
}
#endif
@@ -365,41 +347,45 @@ void pwm_lld_start(PWMDriver *pwmp) {
RCC->APB1RSTR = 0;
NVICEnableVector(TIM5_IRQn,
CORTEX_PRIORITY_MASK(STM32_PWM_TIM5_IRQ_PRIORITY));
+ clock = STM32_TIMCLK1;
}
#endif
-
/* All channels configured in PWM1 mode with preload enabled and will
stay that way until the driver is stopped.*/
- pwmp->pd_tim->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 |
- TIM_CCMR1_OC1PE |
- TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 |
- TIM_CCMR1_OC2PE;
- pwmp->pd_tim->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 |
- TIM_CCMR2_OC3PE |
- TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 |
- TIM_CCMR2_OC4PE;
+ pwmp->tim->CCMR1 = TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2 |
+ TIM_CCMR1_OC1PE |
+ TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2 |
+ TIM_CCMR1_OC2PE;
+ pwmp->tim->CCMR2 = TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2 |
+ TIM_CCMR2_OC3PE |
+ TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2 |
+ TIM_CCMR2_OC4PE;
}
else {
/* Driver re-configuration scenario, it must be stopped first.*/
- /* Really required ?????????? */
- pwmp->pd_tim->CR1 = 0; /* Timer stopped. */
- pwmp->pd_tim->CR2 = 0; /* Timer stopped. */
- pwmp->pd_tim->SMCR = 0; /* Slave mode disabled. */
- pwmp->pd_tim->CCR1 = 0; /* Comparator 1 disabled. */
- pwmp->pd_tim->CCR2 = 0; /* Comparator 2 disabled. */
- pwmp->pd_tim->CCR3 = 0; /* Comparator 3 disabled. */
- pwmp->pd_tim->CCR4 = 0; /* Comparator 4 disabled. */
- pwmp->pd_tim->CNT = 0;
+ pwmp->tim->CR1 = 0; /* Timer disabled. */
+ pwmp->tim->DIER = 0; /* All IRQs disabled. */
+ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
+ pwmp->tim->CCR1 = 0; /* Comparator 1 disabled. */
+ pwmp->tim->CCR2 = 0; /* Comparator 2 disabled. */
+ pwmp->tim->CCR3 = 0; /* Comparator 3 disabled. */
+ pwmp->tim->CCR4 = 0; /* Comparator 4 disabled. */
+ pwmp->tim->CNT = 0; /* Counter reset to zero. */
}
/* Timer configuration.*/
- pwmp->pd_tim->CR2 = pwmp->pd_config->pc_cr2;
- pwmp->pd_tim->PSC = pwmp->pd_config->pc_psc;
- pwmp->pd_tim->ARR = pwmp->pd_config->pc_arr;
+ psc = (clock / pwmp->config->frequency) - 1;
+ chDbgAssert((psc <= 0xFFFF) &&
+ ((psc + 1) * pwmp->config->frequency) == clock,
+ "pwm_lld_start(), #1", "invalid frequency");
+ pwmp->tim->PSC = (uint16_t)psc;
+ pwmp->tim->ARR = (uint16_t)(pwmp->period - 1);
+ pwmp->tim->CR2 = pwmp->config->cr2;
+
/* Output enables and polarities setup.*/
ccer = 0;
- switch (pwmp->pd_config->pc_channels[0].pcc_mode) {
+ switch (pwmp->config->channels[0].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= TIM_CCER_CC1P;
case PWM_OUTPUT_ACTIVE_HIGH:
@@ -407,7 +393,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
default:
;
}
- switch (pwmp->pd_config->pc_channels[1].pcc_mode) {
+ switch (pwmp->config->channels[1].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= TIM_CCER_CC2P;
case PWM_OUTPUT_ACTIVE_HIGH:
@@ -415,7 +401,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
default:
;
}
- switch (pwmp->pd_config->pc_channels[2].pcc_mode) {
+ switch (pwmp->config->channels[2].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= TIM_CCER_CC3P;
case PWM_OUTPUT_ACTIVE_HIGH:
@@ -423,7 +409,7 @@ void pwm_lld_start(PWMDriver *pwmp) {
default:
;
}
- switch (pwmp->pd_config->pc_channels[3].pcc_mode) {
+ switch (pwmp->config->channels[3].mode & PWM_OUTPUT_MASK) {
case PWM_OUTPUT_ACTIVE_LOW:
ccer |= TIM_CCER_CC4P;
case PWM_OUTPUT_ACTIVE_HIGH:
@@ -431,13 +417,46 @@ void pwm_lld_start(PWMDriver *pwmp) {
default:
;
}
- pwmp->pd_tim->CCER = ccer;
- pwmp->pd_tim->EGR = TIM_EGR_UG; /* Update event. */
- pwmp->pd_tim->SR = 0; /* Clear pending IRQs. */
- pwmp->pd_tim->DIER = pwmp->pd_config->pc_callback == NULL ? 0 : TIM_DIER_UIE;
- pwmp->pd_tim->BDTR = TIM_BDTR_MOE;
+#if STM32_PWM_USE_ADVANCED
+ if (&PWMD1 == pwmp) {
+ switch (pwmp->config->channels[0].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= TIM_CCER_CC1NP;
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= TIM_CCER_CC1NE;
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[1].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= TIM_CCER_CC2NP;
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= TIM_CCER_CC2NE;
+ default:
+ ;
+ }
+ switch (pwmp->config->channels[2].mode & PWM_COMPLEMENTARY_OUTPUT_MASK) {
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW:
+ ccer |= TIM_CCER_CC3NP;
+ case PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH:
+ ccer |= TIM_CCER_CC3NE;
+ default:
+ ;
+ }
+ }
+#endif /* STM32_PWM_USE_ADVANCED*/
+
+ pwmp->tim->CCER = ccer;
+ pwmp->tim->EGR = TIM_EGR_UG; /* Update event. */
+ pwmp->tim->DIER = pwmp->config->callback == NULL ? 0 : TIM_DIER_UIE;
+ pwmp->tim->SR = 0; /* Clear pending IRQs. */
+#if STM32_PWM_USE_ADVANCED
+ pwmp->tim->BDTR = pwmp->config->bdtr | TIM_BDTR_MOE;
+#else
+ pwmp->tim->BDTR = TIM_BDTR_MOE;
+#endif
/* Timer configured and started.*/
- pwmp->pd_tim->CR1 = TIM_CR1_ARPE | TIM_CR1_URS | TIM_CR1_CEN;
+ pwmp->tim->CR1 = TIM_CR1_ARPE | TIM_CR1_URS | TIM_CR1_CEN;
}
/**
@@ -448,20 +467,13 @@ void pwm_lld_start(PWMDriver *pwmp) {
* @notapi
*/
void pwm_lld_stop(PWMDriver *pwmp) {
+
/* If in ready state then disables the PWM clock.*/
- if (pwmp->pd_state == PWM_READY) {
- pwmp->pd_enabled_channels = 0; /* All channels disabled. */
- pwmp->pd_tim->CR1 = 0;
- pwmp->pd_tim->CR2 = 0;
- pwmp->pd_tim->CCER = 0; /* Outputs disabled. */
- pwmp->pd_tim->CCR1 = 0; /* Comparator 1 disabled. */
- pwmp->pd_tim->CCR2 = 0; /* Comparator 2 disabled. */
- pwmp->pd_tim->CCR3 = 0; /* Comparator 3 disabled. */
- pwmp->pd_tim->CCR4 = 0; /* Comparator 4 disabled. */
- pwmp->pd_tim->BDTR = 0;
- pwmp->pd_tim->DIER = 0;
- pwmp->pd_tim->SR = 0;
- pwmp->pd_tim->EGR = TIM_EGR_UG; /* Update event. */
+ if (pwmp->state == PWM_READY) {
+ pwmp->tim->CR1 = 0; /* Timer disabled. */
+ pwmp->tim->DIER = 0; /* All IRQs disabled. */
+ pwmp->tim->SR = 0; /* Clear eventual pending IRQs. */
+ pwmp->tim->BDTR = 0;
#if STM32_PWM_USE_TIM1
if (&PWMD1 == pwmp) {
@@ -499,6 +511,9 @@ void pwm_lld_stop(PWMDriver *pwmp) {
/**
* @brief Enables a PWM channel.
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is active using the specified configuration.
+ * @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
@@ -510,23 +525,26 @@ void pwm_lld_enable_channel(PWMDriver *pwmp,
pwmchannel_t channel,
pwmcnt_t width) {
- *(&pwmp->pd_tim->CCR1 + (channel * 2)) = width; /* New duty cycle. */
- if ((pwmp->pd_enabled_channels & (1 << channel)) == 0) {
- /* The channel is not enabled yet.*/
- pwmp->pd_enabled_channels |= (1 << channel);
- /* If there is a callback associated to the channel then the proper
- interrupt is cleared and enabled.*/
- if (pwmp->pd_config->pc_channels[channel].pcc_callback) {
- pwmp->pd_tim->SR = ~(2 << channel);
- pwmp->pd_tim->DIER |= (2 << channel);
+ *(&pwmp->tim->CCR1 + (channel * 2)) = width; /* New duty cycle. */
+ /* If there is a callback defined for the channel then the associated
+ interrupt must be enabled.*/
+ if (pwmp->config->channels[channel].callback != NULL) {
+ uint32_t dier = pwmp->tim->DIER;
+ /* If the IRQ is not already enabled care must be taken to clear it,
+ it is probably already pending because the timer is running.*/
+ if ((dier & (2 << channel)) == 0) {
+ pwmp->tim->DIER = dier | (2 << channel);
+ pwmp->tim->SR = ~(2 << channel);
}
}
}
/**
* @brief Disables a PWM channel.
- * @details The channel is disabled and its output line returned to the
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The channel is disabled and its output line returned to the
* idle state.
+ * @note The function has effect at the next cycle start.
*
* @param[in] pwmp pointer to a @p PWMDriver object
* @param[in] channel PWM channel identifier (0...PWM_CHANNELS-1)
@@ -535,9 +553,8 @@ void pwm_lld_enable_channel(PWMDriver *pwmp,
*/
void pwm_lld_disable_channel(PWMDriver *pwmp, pwmchannel_t channel) {
- *(&pwmp->pd_tim->CCR1 + (channel * 2)) = 0;
- pwmp->pd_tim->DIER &= ~(2 << channel);
- pwmp->pd_enabled_channels &= ~(1 << channel);
+ *(&pwmp->tim->CCR1 + (channel * 2)) = 0;
+ pwmp->tim->DIER &= ~(2 << channel);
}
#endif /* HAL_USE_PWM */
diff --git a/os/hal/platforms/STM32/pwm_lld.h b/os/hal/platforms/STM32/pwm_lld.h
index 1e9dd855a..2b3ce7183 100644
--- a/os/hal/platforms/STM32/pwm_lld.h
+++ b/os/hal/platforms/STM32/pwm_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -37,15 +38,55 @@
/**
* @brief Number of PWM channels per PWM driver.
*/
-#define PWM_CHANNELS 4
+#define PWM_CHANNELS 4
+
+/**
+ * @brief Complementary output modes mask.
+ * @note This is an STM32-specific setting.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_MASK 0xF0
+
+/**
+ * @brief Complementary output not driven.
+ * @note This is an STM32-specific setting.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_DISABLED 0x00
+
+/**
+ * @brief Complementary output, active is logic level one.
+ * @note This is an STM32-specific setting.
+ * @note This setting is only available if the configuration option
+ * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
+ * timers TIM1 and TIM8.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_HIGH 0x10
+
+/**
+ * @brief Complementary output, active is logic level zero.
+ * @note This is an STM32-specific setting.
+ * @note This setting is only available if the configuration option
+ * @p STM32_PWM_USE_ADVANCED is set to TRUE and only for advanced
+ * timers TIM1 and TIM8.
+ */
+#define PWM_COMPLEMENTARY_OUTPUT_ACTIVE_LOW 0x20
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
/**
- * @brief PWM1 driver enable switch.
- * @details If set to @p TRUE the support for PWM1 is included.
+ * @brief If advanced timer features switch.
+ * @details If set to @p TRUE the advanced features for TIM1 and TIM8 are
+ * enabled.
+ * @note The default is @p TRUE.
+ */
+#if !defined(STM32_PWM_USE_ADVANCED) || defined(__DOXYGEN__)
+#define STM32_PWM_USE_ADVANCED TRUE
+#endif
+
+/**
+ * @brief PWMD1 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD1 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM1) || defined(__DOXYGEN__)
@@ -53,8 +94,8 @@
#endif
/**
- * @brief PWM2 driver enable switch.
- * @details If set to @p TRUE the support for PWM2 is included.
+ * @brief PWMD2 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD2 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM2) || defined(__DOXYGEN__)
@@ -62,8 +103,8 @@
#endif
/**
- * @brief PWM3 driver enable switch.
- * @details If set to @p TRUE the support for PWM3 is included.
+ * @brief PWMD3 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD3 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM3) || defined(__DOXYGEN__)
@@ -71,8 +112,8 @@
#endif
/**
- * @brief PWM4 driver enable switch.
- * @details If set to @p TRUE the support for PWM4 is included.
+ * @brief PWMD4 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD4 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM4) || defined(__DOXYGEN__)
@@ -80,8 +121,8 @@
#endif
/**
- * @brief PWM5 driver enable switch.
- * @details If set to @p TRUE the support for PWM5 is included.
+ * @brief PWMD5 driver enable switch.
+ * @details If set to @p TRUE the support for PWMD5 is included.
* @note The default is @p TRUE.
*/
#if !defined(STM32_PWM_USE_TIM5) || defined(__DOXYGEN__)
@@ -89,35 +130,35 @@
#endif
/**
- * @brief PWM1 interrupt priority level setting.
+ * @brief PWMD1 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM1_IRQ_PRIORITY 7
#endif
/**
- * @brief PWM2 interrupt priority level setting.
+ * @brief PWMD2 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM2_IRQ_PRIORITY 7
#endif
/**
- * @brief PWM3 interrupt priority level setting.
+ * @brief PWMD3 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM3_IRQ_PRIORITY 7
#endif
/**
- * @brief PWM4 interrupt priority level setting.
+ * @brief PWMD4 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM4_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM4_IRQ_PRIORITY 7
#endif
/**
- * @brief PWM5 interrupt priority level setting.
+ * @brief PWMD5 interrupt priority level setting.
*/
#if !defined(STM32_PWM_TIM5_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_PWM_TIM5_IRQ_PRIORITY 7
@@ -153,11 +194,20 @@
#error "PWM driver activated but no TIM peripheral assigned"
#endif
+#if STM32_PWM_USE_ADVANCED && !STM32_PWM_USE_TIM1
+#error "advanced mode selected but no advanced timer assigned"
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
/**
+ * @brief PWM mode type.
+ */
+typedef uint32_t pwmmode_t;
+
+/**
* @brief PWM channel type.
*/
typedef uint8_t pwmchannel_t;
@@ -168,31 +218,19 @@ typedef uint8_t pwmchannel_t;
typedef uint16_t pwmcnt_t;
/**
- * @brief Type of a structure representing an PWM driver.
- */
-typedef struct PWMDriver PWMDriver;
-
-/**
- * @brief PWM notification callback type.
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- */
-typedef void (*pwmcallback_t)(PWMDriver *pwmp);
-
-/**
* @brief PWM driver channel configuration structure.
*/
typedef struct {
/**
* @brief Channel active logic level.
*/
- pwmmode_t pcc_mode;
+ pwmmode_t mode;
/**
* @brief Channel callback pointer.
* @note This callback is invoked on the channel compare event. If set to
* @p NULL then the callback is disabled.
*/
- pwmcallback_t pcc_callback;
+ pwmcallback_t callback;
/* End of the mandatory fields.*/
} PWMChannelConfig;
@@ -201,29 +239,40 @@ typedef struct {
*/
typedef struct {
/**
+ * @brief Timer clock in Hz.
+ * @note The low level can use assertions in order to catch invalid
+ * frequency specifications.
+ */
+ uint32_t frequency;
+ /**
+ * @brief PWM period in ticks.
+ * @note The low level can use assertions in order to catch invalid
+ * period specifications.
+ */
+ pwmcnt_t period;
+ /**
* @brief Periodic callback pointer.
* @note This callback is invoked on PWM counter reset. If set to
* @p NULL then the callback is disabled.
*/
- pwmcallback_t pc_callback;
+ pwmcallback_t callback;
/**
* @brief Channels configurations.
*/
- PWMChannelConfig pc_channels[PWM_CHANNELS];
+ PWMChannelConfig channels[PWM_CHANNELS];
/* End of the mandatory fields.*/
/**
- * @brief TIM PSC (pre-scaler) register initialization data.
- */
- uint16_t pc_psc;
- /**
- * @brief TIM ARR (auto-reload) register initialization data.
- */
- uint16_t pc_arr;
- /**
* @brief TIM CR2 register initialization data.
* @note The value of this field should normally be equal to zero.
*/
- uint16_t pc_cr2;
+ uint16_t cr2;
+#if STM32_PWM_USE_ADVANCED || defined(__DOXYGEN__)
+ /**
+ * @brief TIM BDTR (break & dead-time) register initialization data.
+ * @note The value of this field should normally be equal to zero.
+ */ \
+ uint16_t bdtr;
+#endif
} PWMConfig;
/**
@@ -233,23 +282,23 @@ struct PWMDriver {
/**
* @brief Driver state.
*/
- pwmstate_t pd_state;
+ pwmstate_t state;
/**
* @brief Current driver configuration data.
*/
- const PWMConfig *pd_config;
+ const PWMConfig *config;
+ /**
+ * @brief Current PWM period in ticks.
+ */
+ pwmcnt_t period;
#if defined(PWM_DRIVER_EXT_FIELDS)
PWM_DRIVER_EXT_FIELDS
#endif
/* End of the mandatory fields.*/
/**
- * @brief Bit mask of the enabled channels.
- */
- uint32_t pd_enabled_channels;
- /**
* @brief Pointer to the TIMx registers block.
*/
- TIM_TypeDef *pd_tim;
+ TIM_TypeDef *tim;
};
/*===========================================================================*/
@@ -257,88 +306,23 @@ struct PWMDriver {
/*===========================================================================*/
/**
- * @brief PWM clock prescaler initialization utility.
- * @note The real clock value is rounded to the lower valid value, please
- * make sure that the source clock frequency is a multiple of the
- * requested PWM clock frequency.
- * @note The calculated value must fit into an unsigned 16 bits integer.
- *
- * @param[in] clksrc clock source frequency, depending on the target timer
- * cell it can be one of:
- * - STM32_TIMCLK1
- * - STM32_TIMCLK2
- * .
- * Please refer to the STM32 HAL driver documentation
- * and/or the STM32 Reference Manual for the right clock
- * source.
- * @param[in] pwmclk PWM clock frequency in cycles
- * @return The value to be stored in the @p pc_psc field of the
- * @p PWMConfig structure.
- */
-#define PWM_COMPUTE_PSC(clksrc, pwmclk) \
- ((uint16_t)(((clksrc) / (pwmclk)) - 1))
-
-/**
- * @brief PWM cycle period initialization utility.
- * @note The calculated value must fit into an unsigned 16 bits integer.
- *
- * @param[in] pwmclk PWM clock frequency in cycles
- * @param[in] pwmperiod PWM cycle period in nanoseconds
- * @return The value to be stored in the @p pc_arr field of the
- * @p PWMConfig structure.
- */
-#define PWM_COMPUTE_ARR(pwmclk, pwmperiod) \
- ((uint16_t)(((pwmclk) / (1000000000 / (pwmperiod))) - 1))
-
-/**
- * @brief Converts from fraction to pulse width.
- * @note Be careful with rounding errors, this is integer math not magic.
- * You can specify tenths of thousandth but make sure you have the
- * proper hardware resolution by carefully choosing the clock source
- * and prescaler settings, see @p PWM_COMPUTE_PSC.
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] numerator numerator of the fraction
- * @param[in] denominator percentage as an integer between 0 and numerator
- * @return The pulse width to be passed to @p pwmEnableChannel().
- *
- * @api
- */
-#define PWM_FRACTION_TO_WIDTH(pwmp, numerator, denominator) \
- ((uint16_t)((((uint32_t)(pwmp)->pd_config->pc_arr + 1UL) * \
- (uint32_t)(denominator)) / (uint32_t)(numerator)))
-
-/**
- * @brief Converts from degrees to pulse width.
- * @note Be careful with rounding errors, this is integer math not magic.
- * You can specify hundredths of degrees but make sure you have the
- * proper hardware resolution by carefully choosing the clock source
- * and prescaler settings, see @p PWM_COMPUTE_PSC.
- *
- * @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] degrees degrees as an integer between 0 and 36000
- * @return The pulse width to be passed to @p pwmEnableChannel().
- *
- * @api
- */
-#define PWM_DEGREES_TO_WIDTH(pwmp, degrees) \
- PWM_FRACTION_TO_WIDTH(pwmp, 36000, degrees)
-
-/**
- * @brief Converts from percentage to pulse width.
- * @note Be careful with rounding errors, this is integer math not magic.
- * You can specify tenths of thousandth but make sure you have the
- * proper hardware resolution by carefully choosing the clock source
- * and prescaler settings, see @p PWM_COMPUTE_PSC.
+ * @brief Changes the period the PWM peripheral.
+ * @details This function changes the period of a PWM unit that has already
+ * been activated using @p pwmStart().
+ * @pre The PWM unit must have been activated using @p pwmStart().
+ * @post The PWM unit period is changed to the new value.
+ * @note The function has effect at the next cycle start.
+ * @note If a period is specified that is shorter than the pulse width
+ * programmed in one of the channels then the behavior is not
+ * guaranteed.
*
* @param[in] pwmp pointer to a @p PWMDriver object
- * @param[in] percentage percentage as an integer between 0 and 10000
- * @return The pulse width to be passed to @p pwmEnableChannel().
+ * @param[in] period new cycle time in ticks
*
- * @api
+ * @notapi
*/
-#define PWM_PERCENTAGE_TO_WIDTH(pwmp, percentage) \
- PWM_FRACTION_TO_WIDTH(pwmp, 10000, percentage)
+#define pwm_lld_change_period(pwmp, period) \
+ ((pwmp)->tim->ARR = (uint16_t)((period) - 1))
/*===========================================================================*/
/* External declarations. */
diff --git a/os/hal/platforms/STM32/sdc_lld.c b/os/hal/platforms/STM32/sdc_lld.c
new file mode 100644
index 000000000..a88ad53fa
--- /dev/null
+++ b/os/hal/platforms/STM32/sdc_lld.c
@@ -0,0 +1,722 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/sdc_lld.c
+ * @brief STM32 SDC subsystem low level driver source.
+ *
+ * @addtogroup SDC
+ * @{
+ */
+
+#include <string.h>
+
+#include "ch.h"
+#include "hal.h"
+
+#if HAL_USE_SDC || defined(__DOXYGEN__)
+
+/*===========================================================================*/
+/* Driver exported variables. */
+/*===========================================================================*/
+
+/** @brief SDCD1 driver identifier.*/
+SDCDriver SDCD1;
+
+/*===========================================================================*/
+/* Driver local variables. */
+/*===========================================================================*/
+
+#if STM32_SDC_UNALIGNED_SUPPORT
+/**
+ * @brief Buffer for temporary storage during unaligned transfers.
+ */
+static union {
+ uint32_t alignment;
+ uint8_t buf[SDC_BLOCK_SIZE];
+} u;
+#endif
+
+/*===========================================================================*/
+/* Driver local functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer, it must be aligned to
+ * four bytes boundary
+ * @param[in] n number of blocks to read
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * read.
+ * @retval TRUE operation failed, the state of the buffer is uncertain.
+ *
+ * @notapi
+ */
+static bool_t sdc_lld_read_multiple(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t n) {
+ uint32_t resp[1];
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (sdc_wait_for_transfer_state(sdcp))
+ return TRUE;
+
+ /* Prepares the DMA channel for reading.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC);
+
+ /* Setting up data transfer.
+ Options: Card to Controller, Block mode, DMA mode, 512 bytes blocks.*/
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_DATAENDIE | SDIO_MASK_STBITERRIE;
+ SDIO->DLEN = n * SDC_BLOCK_SIZE;
+ SDIO->DCTRL = SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ /* DMA channel activation.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* Read multiple blocks command.*/
+ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
+ startblk *= SDC_BLOCK_SIZE;
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_MULTIPLE_BLOCK,
+ startblk, resp) ||
+ SDC_R1_ERROR(resp[0]))
+ goto error;
+
+ chSysLock();
+ if (SDIO->MASK != 0) {
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_multiple(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_multiple(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/**
+ * @brief Reads one block.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer, it must be aligned to
+ * four bytes boundary
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * read.
+ * @retval TRUE operation failed, the state of the buffer is uncertain.
+ *
+ * @notapi
+ */
+static bool_t sdc_lld_read_single(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf) {
+ uint32_t resp[1];
+
+ /* Checks for errors and waits for the card to be ready for reading.*/
+ if (sdc_wait_for_transfer_state(sdcp))
+ return TRUE;
+
+ /* Prepares the DMA channel for reading.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ SDC_BLOCK_SIZE / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC);
+
+ /* Setting up data transfer.
+ Options: Card to Controller, Block mode, DMA mode, 512 bytes blocks.*/
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_DATAENDIE | SDIO_MASK_STBITERRIE;
+ SDIO->DLEN = SDC_BLOCK_SIZE;
+ SDIO->DCTRL = SDIO_DCTRL_DTDIR |
+ SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ /* DMA channel activation.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* Read single block command.*/
+ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
+ startblk *= SDC_BLOCK_SIZE;
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_READ_SINGLE_BLOCK,
+ startblk, resp) ||
+ SDC_R1_ERROR(resp[0]))
+ goto error;
+
+ chSysLock();
+ if (SDIO->MASK != 0) {
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_single(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_read_single(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return FALSE;
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer, it must be aligned to
+ * four bytes boundary
+ * @param[in] n number of blocks to write
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * written.
+ * @retval TRUE operation failed.
+ *
+ * @notapi
+ */
+static bool_t sdc_lld_write_multiple(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t n) {
+ uint32_t resp[1];
+
+ /* Checks for errors and waits for the card to be ready for writing.*/
+ if (sdc_wait_for_transfer_state(sdcp))
+ return TRUE;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ (n * SDC_BLOCK_SIZE) / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC | DMA_CCR1_DIR);
+
+ /* Write multiple blocks command.*/
+ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
+ startblk *= SDC_BLOCK_SIZE;
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_MULTIPLE_BLOCK,
+ startblk, resp) ||
+ SDC_R1_ERROR(resp[0]))
+ return TRUE;
+
+ /* Setting up data transfer.
+ Options: Controller to Card, Block mode, DMA mode, 512 bytes blocks.*/
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE |
+ SDIO_MASK_STBITERRIE;
+ SDIO->DLEN = n * SDC_BLOCK_SIZE;
+ SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ /* DMA channel activation.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
+ chSysLock();
+ if (SDIO->MASK != 0) {
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_write_multiple(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_write_multiple(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_STOP_TRANSMISSION, 0, resp);
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/**
+ * @brief Writes one block.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer, it must be aligned to
+ * four bytes boundary
+ * @param[in] n number of blocks to write
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * written.
+ * @retval TRUE operation failed.
+ *
+ * @notapi
+ */
+static bool_t sdc_lld_write_single(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf) {
+ uint32_t resp[1];
+
+ /* Checks for errors and waits for the card to be ready for writing.*/
+ if (sdc_wait_for_transfer_state(sdcp))
+ return TRUE;
+
+ /* Prepares the DMA channel for writing.*/
+ dmaChannelSetup(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4],
+ SDC_BLOCK_SIZE / sizeof (uint32_t), buf,
+ (STM32_SDC_SDIO_DMA_PRIORITY << 12) |
+ DMA_CCR1_PSIZE_1 | DMA_CCR1_MSIZE_1 |
+ DMA_CCR1_MINC | DMA_CCR1_DIR);
+
+ /* Write single block command.*/
+ if ((sdcp->cardmode & SDC_MODE_HIGH_CAPACITY) == 0)
+ startblk *= SDC_BLOCK_SIZE;
+ if (sdc_lld_send_cmd_short_crc(sdcp, SDC_CMD_WRITE_BLOCK,
+ startblk, resp) ||
+ SDC_R1_ERROR(resp[0]))
+ return TRUE;
+
+ /* Setting up data transfer.
+ Options: Controller to Card, Block mode, DMA mode, 512 bytes blocks.*/
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = SDIO_MASK_DCRCFAILIE | SDIO_MASK_DTIMEOUTIE |
+ SDIO_MASK_DATAENDIE | SDIO_MASK_TXUNDERRIE |
+ SDIO_MASK_STBITERRIE;
+ SDIO->DLEN = SDC_BLOCK_SIZE;
+ SDIO->DCTRL = SDIO_DCTRL_DBLOCKSIZE_3 | SDIO_DCTRL_DBLOCKSIZE_0 |
+ SDIO_DCTRL_DMAEN |
+ SDIO_DCTRL_DTEN;
+
+ /* DMA channel activation.*/
+ dmaEnableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+
+ /* Note the mask is checked before going to sleep because the interrupt
+ may have occurred before reaching the critical zone.*/
+ chSysLock();
+ if (SDIO->MASK != 0) {
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_write_single(), #1", "not NULL");
+ sdcp->thread = chThdSelf();
+ chSchGoSleepS(THD_STATE_SUSPENDED);
+ chDbgAssert(sdcp->thread == NULL,
+ "sdc_lld_write_single(), #2", "not NULL");
+ }
+ if ((SDIO->STA & SDIO_STA_DATAEND) == 0) {
+ chSysUnlock();
+ goto error;
+ }
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->DCTRL = 0;
+ chSysUnlock();
+
+ return FALSE;
+error:
+ dmaDisableChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ SDIO->ICR = 0xFFFFFFFF;
+ SDIO->MASK = 0;
+ SDIO->DCTRL = 0;
+ return TRUE;
+}
+
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
+
+/**
+ * @brief SDIO IRQ handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(SDIO_IRQHandler) {
+
+ CH_IRQ_PROLOGUE();
+
+ chSysLockFromIsr();
+ if (SDCD1.thread != NULL) {
+ chSchReadyI(SDCD1.thread);
+ SDCD1.thread = NULL;
+ }
+ chSysUnlockFromIsr();
+
+ /* Disables the source but the status flags are not reset because the
+ read/write functions need to check them.*/
+ SDIO->MASK = 0;
+
+ CH_IRQ_EPILOGUE();
+}
+
+/*===========================================================================*/
+/* Driver exported functions. */
+/*===========================================================================*/
+
+/**
+ * @brief Low level SDC driver initialization.
+ *
+ * @notapi
+ */
+void sdc_lld_init(void) {
+
+ sdcObjectInit(&SDCD1);
+ SDCD1.thread = NULL;
+}
+
+/**
+ * @brief Configures and activates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object, must be @p NULL,
+ * this driver does not require any configuration
+ *
+ * @notapi
+ */
+void sdc_lld_start(SDCDriver *sdcp) {
+
+ if (sdcp->state == SDC_STOP) {
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA2_ID, STM32_DMA_CHANNEL_4, NULL, NULL);
+ dmaChannelSetPeripheral(&STM32_DMA2->channels[STM32_DMA_CHANNEL_4], &SDIO->FIFO);
+ NVICEnableVector(SDIO_IRQn,
+ CORTEX_PRIORITY_MASK(STM32_SDC_SDIO_IRQ_PRIORITY));
+ RCC->AHBENR |= RCC_AHBENR_SDIOEN;
+ }
+ /* Configuration, card clock is initially stopped.*/
+ SDIO->POWER = 0;
+ SDIO->CLKCR = 0;
+ SDIO->DCTRL = 0;
+ SDIO->DTIMER = STM32_SDC_DATATIMEOUT;
+}
+
+/**
+ * @brief Deactivates the SDC peripheral.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop(SDCDriver *sdcp) {
+
+ if ((sdcp->state == SDC_READY) || (sdcp->state == SDC_ACTIVE)) {
+ SDIO->POWER = 0;
+ SDIO->CLKCR = 0;
+ SDIO->DCTRL = 0;
+ SDIO->DTIMER = 0;
+
+ /* Clock deactivation.*/
+ NVICDisableVector(SDIO_IRQn);
+ dmaRelease(STM32_DMA2_ID, STM32_DMA_CHANNEL_4);
+ }
+}
+
+/**
+ * @brief Starts the SDIO clock and sets it to init mode (400KHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_start_clk(SDCDriver *sdcp) {
+
+ (void)sdcp;
+ /* Initial clock setting: 400KHz, 1bit mode.*/
+ SDIO->CLKCR = STM32_SDIO_DIV_LS;
+ SDIO->POWER |= SDIO_POWER_PWRCTRL_0 | SDIO_POWER_PWRCTRL_1;
+ SDIO->CLKCR |= SDIO_CLKCR_CLKEN;
+}
+
+/**
+ * @brief Sets the SDIO clock to data mode (25MHz or less).
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_set_data_clk(SDCDriver *sdcp) {
+
+ (void)sdcp;
+ SDIO->CLKCR = (SDIO->CLKCR & 0xFFFFFF00) | STM32_SDIO_DIV_HS;
+}
+
+/**
+ * @brief Stops the SDIO clock.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ *
+ * @notapi
+ */
+void sdc_lld_stop_clk(SDCDriver *sdcp) {
+
+ (void)sdcp;
+ SDIO->CLKCR = 0;
+ SDIO->POWER = 0;
+}
+
+/**
+ * @brief Switches the bus to 4 bits mode.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] mode bus mode
+ *
+ * @notapi
+ */
+void sdc_lld_set_bus_mode(SDCDriver *sdcp, sdcbusmode_t mode) {
+ uint32_t clk = SDIO->CLKCR & ~SDIO_CLKCR_WIDBUS;
+
+ (void)sdcp;
+ switch (mode) {
+ case SDC_MODE_1BIT:
+ SDIO->CLKCR = clk;
+ break;
+ case SDC_MODE_4BIT:
+ SDIO->CLKCR = clk | SDIO_CLKCR_WIDBUS_0;
+ break;
+ case SDC_MODE_8BIT:
+ SDIO->CLKCR = clk | SDIO_CLKCR_WIDBUS_1;
+ }
+}
+
+/**
+ * @brief Sends an SDIO command with no response expected.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ *
+ * @notapi
+ */
+void sdc_lld_send_cmd_none(SDCDriver *sdcp, uint8_t cmd, uint32_t arg) {
+
+ (void)sdcp;
+ SDIO->ARG = arg;
+ SDIO->CMD = (uint32_t)cmd | SDIO_CMD_CPSMEN;
+ while ((SDIO->STA & SDIO_STA_CMDSENT) == 0)
+ ;
+ SDIO->ICR = SDIO_ICR_CMDSENTC;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected.
+ * @note The CRC is not verified.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ * @return The operation status.
+ * @retval FALSE the operation succeeded.
+ * @retval TRUE the operation failed because timeout, CRC check or
+ * other errors.
+ *
+ * @notapi
+ */
+bool_t sdc_lld_send_cmd_short(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ (void)sdcp;
+ SDIO->ARG = arg;
+ SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN;
+ while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ SDIO->ICR = SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC;
+ if ((sta & (SDIO_STA_CTIMEOUT)) != 0)
+ return TRUE;
+ *resp = SDIO->RESP1;
+ return FALSE;
+}
+
+/**
+ * @brief Sends an SDIO command with a short response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (one word)
+ * @return The operation status.
+ * @retval FALSE the operation succeeded.
+ * @retval TRUE the operation failed because timeout, CRC check or
+ * other errors.
+ *
+ * @notapi
+ */
+bool_t sdc_lld_send_cmd_short_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+ uint32_t sta;
+
+ (void)sdcp;
+ SDIO->ARG = arg;
+ SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_CPSMEN;
+ while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ SDIO->ICR = SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC;
+ if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0)
+ return TRUE;
+ *resp = SDIO->RESP1;
+ return FALSE;
+}
+
+/**
+ * @brief Sends an SDIO command with a long response expected and CRC.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] cmd card command
+ * @param[in] arg command argument
+ * @param[out] resp pointer to the response buffer (four words)
+ * @return The operation status.
+ * @retval FALSE the operation succeeded.
+ * @retval TRUE the operation failed because timeout, CRC check or
+ * other errors.
+ *
+ * @notapi
+ */
+bool_t sdc_lld_send_cmd_long_crc(SDCDriver *sdcp, uint8_t cmd, uint32_t arg,
+ uint32_t *resp) {
+
+ uint32_t sta;
+
+ (void)sdcp;
+ SDIO->ARG = arg;
+ SDIO->CMD = (uint32_t)cmd | SDIO_CMD_WAITRESP_0 | SDIO_CMD_WAITRESP_1 |
+ SDIO_CMD_CPSMEN;
+ while (((sta = SDIO->STA) & (SDIO_STA_CMDREND | SDIO_STA_CTIMEOUT |
+ SDIO_STA_CCRCFAIL)) == 0)
+ ;
+ SDIO->ICR = SDIO_ICR_CMDRENDC | SDIO_ICR_CTIMEOUTC | SDIO_ICR_CCRCFAILC;
+ if ((sta & (SDIO_STA_CTIMEOUT | SDIO_STA_CCRCFAIL)) != 0)
+ return TRUE;
+ *resp = SDIO->RESP1;
+ return FALSE;
+}
+
+/**
+ * @brief Reads one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to read
+ * @param[out] buf pointer to the read buffer
+ * @param[in] n number of blocks to read
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * read.
+ * @retval TRUE operation failed, the state of the buffer is uncertain.
+ *
+ * @notapi
+ */
+bool_t sdc_lld_read(SDCDriver *sdcp, uint32_t startblk,
+ uint8_t *buf, uint32_t n) {
+
+#if STM32_SDC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < n; i++) {
+ if (sdc_lld_read_single(sdcp, startblk, u.buf))
+ return TRUE;
+ memcpy(buf, u.buf, SDC_BLOCK_SIZE);
+ buf += SDC_BLOCK_SIZE;
+ startblk++;
+ }
+ return FALSE;
+ }
+#endif
+ if (n == 1)
+ return sdc_lld_read_single(sdcp, startblk, buf);
+ return sdc_lld_read_multiple(sdcp, startblk, buf, n);
+}
+
+/**
+ * @brief Writes one or more blocks.
+ *
+ * @param[in] sdcp pointer to the @p SDCDriver object
+ * @param[in] startblk first block to write
+ * @param[out] buf pointer to the write buffer
+ * @param[in] n number of blocks to write
+ * @return The operation status.
+ * @retval FALSE operation succeeded, the requested blocks have been
+ * written.
+ * @retval TRUE operation failed.
+ *
+ * @notapi
+ */
+bool_t sdc_lld_write(SDCDriver *sdcp, uint32_t startblk,
+ const uint8_t *buf, uint32_t n) {
+
+ #if STM32_SDC_UNALIGNED_SUPPORT
+ if (((unsigned)buf & 3) != 0) {
+ uint32_t i;
+ for (i = 0; i < n; i++) {
+ memcpy(u.buf, buf, SDC_BLOCK_SIZE);
+ buf += SDC_BLOCK_SIZE;
+ if (sdc_lld_write_single(sdcp, startblk, u.buf))
+ return TRUE;
+ startblk++;
+ }
+ return FALSE;
+ }
+#endif
+ if (n == 1)
+ return sdc_lld_write_single(sdcp, startblk, buf);
+ return sdc_lld_write_multiple(sdcp, startblk, buf, n);
+}
+
+#endif /* HAL_USE_SDC */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/sdc_lld.h b/os/hal/platforms/STM32/sdc_lld.h
new file mode 100644
index 000000000..5466eacad
--- /dev/null
+++ b/os/hal/platforms/STM32/sdc_lld.h
@@ -0,0 +1,203 @@
+/*
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
+
+ This file is part of ChibiOS/RT.
+
+ ChibiOS/RT is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ ChibiOS/RT is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @file STM32/sdc_lld.h
+ * @brief STM32 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. */
+/*===========================================================================*/
+
+/**
+ * @brief SDIO data timeout in SDIO clock cycles.
+ */
+#if !defined(STM32_SDC_DATATIMEOUT) || defined(__DOXYGEN__)
+#define STM32_SDC_DATATIMEOUT 0x000FFFFF
+#endif
+
+/**
+ * @brief SDIO DMA priority (0..3|lowest..highest).
+ */
+#if !defined(STM32_SDC_SDIO_DMA_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_DMA_PRIORITY 3
+#endif
+
+/**
+ * @brief SDIO interrupt priority level setting.
+ */
+#if !defined(STM32_SDC_SDIO_IRQ_PRIORITY) || defined(__DOXYGEN__)
+#define STM32_SDC_SDIO_IRQ_PRIORITY 9
+#endif
+
+/**
+ * @brief SDIO support for unaligned transfers.
+ */
+#if !defined(STM32_SDC_UNALIGNED_SUPPORT) || defined(__DOXYGEN__)
+#define STM32_SDC_UNALIGNED_SUPPORT TRUE
+#endif
+
+/*===========================================================================*/
+/* Derived constants and error checks. */
+/*===========================================================================*/
+
+#if !STM32_HAS_SDIO
+#error "SDIO not present in the selected device"
+#endif
+
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
+/*
+ * SDIO clock divider.
+ */
+#if STM32_HCLK > 48000000
+#define STM32_SDIO_DIV_HS 0x01
+#define STM32_SDIO_DIV_LS 0xB2
+#else
+#define STM32_SDIO_DIV_HS 0x00
+#define STM32_SDIO_DIV_LS 0x76
+#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 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 Structure representing an SDC driver.
+ */
+struct SDCDriver {
+ /**
+ * @brief Driver state.
+ */
+ sdcstate_t state;
+ /**
+ * @brief Current configuration data.
+ */
+ const SDCConfig *config;
+ /**
+ * @brief Various flags regarding the mounted card.
+ */
+ sdcmode_t cardmode;
+ /**
+ * @brief Card CID.
+ */
+ uint32_t cid[4];
+ /**
+ * @brief Card CSD.
+ */
+ uint32_t csd[4];
+ /**
+ * @brief Card RCA.
+ */
+ uint32_t rca;
+ /* End of the mandatory fields.*/
+ /**
+ * @brief Tthread waiting for I/O completion IRQ.
+ */
+ Thread *thread;
+};
+
+/*===========================================================================*/
+/* Driver macros. */
+/*===========================================================================*/
+
+/*===========================================================================*/
+/* External declarations. */
+/*===========================================================================*/
+
+#if !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_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_ */
+
+/** @} */
diff --git a/os/hal/platforms/STM32/serial_lld.c b/os/hal/platforms/STM32/serial_lld.c
index b20c2a933..5aaa60de9 100644
--- a/os/hal/platforms/STM32/serial_lld.c
+++ b/os/hal/platforms/STM32/serial_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
diff --git a/os/hal/platforms/STM32/serial_lld.h b/os/hal/platforms/STM32/serial_lld.h
index d16e1923d..ceeccff67 100644
--- a/os/hal/platforms/STM32/serial_lld.h
+++ b/os/hal/platforms/STM32/serial_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
diff --git a/os/hal/platforms/STM32/spi_lld.c b/os/hal/platforms/STM32/spi_lld.c
index dfe72822a..d8ae657a7 100644
--- a/os/hal/platforms/STM32/spi_lld.c
+++ b/os/hal/platforms/STM32/spi_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -66,8 +67,8 @@ static uint16_t dummyrx;
* @param[in] spip pointer to the @p SPIDriver object
*/
#define dma_stop(spip) { \
- dmaChannelDisable(spip->spd_dmatx); \
- dmaChannelDisable(spip->spd_dmarx); \
+ dmaChannelDisable(spip->dmatx); \
+ dmaChannelDisable(spip->dmarx); \
}
/**
@@ -76,16 +77,26 @@ static uint16_t dummyrx;
* @param[in] spip pointer to the @p SPIDriver object
*/
#define dma_start(spip) { \
- dmaChannelEnable((spip)->spd_dmarx); \
- dmaChannelEnable((spip)->spd_dmatx); \
+ dmaChannelEnable((spip)->dmarx); \
+ dmaChannelEnable((spip)->dmatx); \
}
/**
- * @brief Shared end-of-transfer service routine.
+ * @brief Shared end-of-rx service routine.
*
* @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
*/
-static void serve_interrupt(SPIDriver *spip) {
+static void spi_lld_serve_rx_interrupt(SPIDriver *spip, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ if ((flags & DMA_ISR_TEIF1) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
+ }
+#else
+ (void)flags;
+#endif
/* Stop everything.*/
dma_stop(spip);
@@ -95,114 +106,29 @@ static void serve_interrupt(SPIDriver *spip) {
_spi_isr_code(spip);
}
-/*===========================================================================*/
-/* Driver interrupt handlers. */
-/*===========================================================================*/
-
-#if STM32_SPI_USE_SPI1 || defined(__DOXYGEN__)
/**
- * @brief SPI1 RX DMA interrupt handler (channel 2).
+ * @brief Shared end-of-tx service routine.
*
- * @isr
+ * @param[in] spip pointer to the @p SPIDriver object
+ * @param[in] flags pre-shifted content of the ISR register
*/
-CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
+static void spi_lld_serve_tx_interrupt(SPIDriver *spip, uint32_t flags) {
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF2) != 0) {
- STM32_SPI_SPI1_DMA_ERROR_HOOK();
+ /* DMA errors handling.*/
+#if defined(STM32_SPI_DMA_ERROR_HOOK)
+ (void)spip;
+ if ((flags & DMA_ISR_TEIF1) != 0) {
+ STM32_SPI_DMA_ERROR_HOOK(spip);
}
- serve_interrupt(&SPID1);
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief SPI1 TX DMA interrupt handler (channel 3).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- STM32_SPI_SPI1_DMA_ERROR_HOOK();
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
-
- CH_IRQ_EPILOGUE();
-}
+#else
+ (void)spip;
+ (void)flags;
#endif
-
-#if STM32_SPI_USE_SPI2 || defined(__DOXYGEN__)
-/**
- * @brief SPI2 RX DMA interrupt handler (channel 4).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) {
- STM32_SPI_SPI2_DMA_ERROR_HOOK();
- }
- serve_interrupt(&SPID2);
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
-
- CH_IRQ_EPILOGUE();
}
-/**
- * @brief SPI2 TX DMA interrupt handler (channel 5).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- STM32_SPI_SPI2_DMA_ERROR_HOOK();
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
-
- CH_IRQ_EPILOGUE();
-}
-#endif
-
-#if STM32_SPI_USE_SPI3 || defined(__DOXYGEN__)
-/**
- * @brief SPI3 RX DMA interrupt handler (DMA2, channel 1).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- if ((STM32_DMA2->ISR & DMA_ISR_TEIF1) != 0) {
- STM32_SPI_SPI3_DMA_ERROR_HOOK();
- }
- serve_interrupt(&SPID3);
- dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_1);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief SPI3 TX DMA2 interrupt handler (DMA2, channel 2).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- STM32_SPI_SPI3_DMA_ERROR_HOOK();
- dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_2);
-
- CH_IRQ_EPILOGUE();
-}
-#endif
+/*===========================================================================*/
+/* Driver interrupt handlers. */
+/*===========================================================================*/
/*===========================================================================*/
/* Driver exported functions. */
@@ -218,33 +144,27 @@ void spi_lld_init(void) {
dummytx = 0xFFFF;
#if STM32_SPI_USE_SPI1
- RCC->APB2RSTR = RCC_APB2RSTR_SPI1RST;
- RCC->APB2RSTR = 0;
spiObjectInit(&SPID1);
- SPID1.spd_thread = NULL;
- SPID1.spd_spi = SPI1;
- SPID1.spd_dmarx = STM32_DMA1_CH2;
- SPID1.spd_dmatx = STM32_DMA1_CH3;
+ SPID1.thread = NULL;
+ SPID1.spi = SPI1;
+ SPID1.dmarx = STM32_DMA1_CH2;
+ SPID1.dmatx = STM32_DMA1_CH3;
#endif
#if STM32_SPI_USE_SPI2
- RCC->APB1RSTR = RCC_APB1RSTR_SPI2RST;
- RCC->APB1RSTR = 0;
spiObjectInit(&SPID2);
- SPID2.spd_thread = NULL;
- SPID2.spd_spi = SPI2;
- SPID2.spd_dmarx = STM32_DMA1_CH4;
- SPID2.spd_dmatx = STM32_DMA1_CH5;
+ SPID2.thread = NULL;
+ SPID2.spi = SPI2;
+ SPID2.dmarx = STM32_DMA1_CH4;
+ SPID2.dmatx = STM32_DMA1_CH5;
#endif
#if STM32_SPI_USE_SPI3
- RCC->APB1RSTR = RCC_APB1RSTR_SPI3RST;
- RCC->APB1RSTR = 0;
spiObjectInit(&SPID3);
- SPID3.spd_thread = NULL;
- SPID3.spd_spi = SPI3;
- SPID3.spd_dmarx = STM32_DMA2_CH1;
- SPID3.spd_dmatx = STM32_DMA2_CH2;
+ SPID3.thread = NULL;
+ SPID3.spi = SPI3;
+ SPID3.dmarx = STM32_DMA2_CH1;
+ SPID3.dmatx = STM32_DMA2_CH2;
#endif
}
@@ -258,10 +178,14 @@ void spi_lld_init(void) {
void spi_lld_start(SPIDriver *spip) {
/* If in stopped state then enables the SPI and DMA clocks.*/
- if (spip->spd_state == SPI_STOP) {
+ if (spip->state == SPI_STOP) {
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_2,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, (void *)spip);
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_3,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip);
NVICEnableVector(DMA1_Channel2_IRQn,
CORTEX_PRIORITY_MASK(STM32_SPI_SPI1_IRQ_PRIORITY));
NVICEnableVector(DMA1_Channel3_IRQn,
@@ -271,7 +195,11 @@ void spi_lld_start(SPIDriver *spip) {
#endif
#if STM32_SPI_USE_SPI2
if (&SPID2 == spip) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_4,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, (void *)spip);
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_5,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip);
NVICEnableVector(DMA1_Channel4_IRQn,
CORTEX_PRIORITY_MASK(STM32_SPI_SPI2_IRQ_PRIORITY));
NVICEnableVector(DMA1_Channel5_IRQn,
@@ -281,7 +209,11 @@ void spi_lld_start(SPIDriver *spip) {
#endif
#if STM32_SPI_USE_SPI3
if (&SPID3 == spip) {
- dmaEnable(DMA2_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA2_ID, STM32_DMA_CHANNEL_1,
+ (stm32_dmaisr_t)spi_lld_serve_rx_interrupt, (void *)spip);
+ dmaAllocate(STM32_DMA2_ID, STM32_DMA_CHANNEL_2,
+ (stm32_dmaisr_t)spi_lld_serve_tx_interrupt, (void *)spip);
NVICEnableVector(DMA2_Channel1_IRQn,
CORTEX_PRIORITY_MASK(STM32_SPI_SPI3_IRQ_PRIORITY));
NVICEnableVector(DMA2_Channel2_IRQn,
@@ -291,23 +223,25 @@ void spi_lld_start(SPIDriver *spip) {
#endif
/* DMA setup.*/
- dmaChannelSetPeripheral(spip->spd_dmarx, &spip->spd_spi->DR);
- dmaChannelSetPeripheral(spip->spd_dmatx, &spip->spd_spi->DR);
+ dmaChannelSetPeripheral(spip->dmarx, &spip->spi->DR);
+ dmaChannelSetPeripheral(spip->dmatx, &spip->spi->DR);
}
/* More DMA setup.*/
- if ((spip->spd_config->spc_cr1 & SPI_CR1_DFF) == 0)
- spip->spd_dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
- DMA_CCR1_TEIE; /* 8 bits transfers. */
+ if ((spip->config->cr1 & SPI_CR1_DFF) == 0)
+ spip->dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
+ DMA_CCR1_TEIE; /* 8 bits transfers. */
else
- spip->spd_dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
- DMA_CCR1_TEIE | DMA_CCR1_MSIZE_0 |
- DMA_CCR1_PSIZE_0; /* 16 bits transfers. */
+ spip->dmaccr = (STM32_SPI_SPI2_DMA_PRIORITY << 12) |
+ DMA_CCR1_TEIE | DMA_CCR1_MSIZE_0 |
+ DMA_CCR1_PSIZE_0; /* 16 bits transfers. */
/* SPI setup and enable.*/
- spip->spd_spi->CR1 = 0;
- spip->spd_spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
- spip->spd_spi->CR1 = spip->spd_config->spc_cr1 | SPI_CR1_MSTR | SPI_CR1_SPE;
+ spip->spi->CR1 = 0;
+ spip->spi->CR1 = spip->config->cr1 | SPI_CR1_MSTR | SPI_CR1_SSM |
+ SPI_CR1_SSI;
+ spip->spi->CR2 = SPI_CR2_SSOE | SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN;
+ spip->spi->CR1 |= SPI_CR1_SPE;
}
/**
@@ -320,16 +254,17 @@ void spi_lld_start(SPIDriver *spip) {
void spi_lld_stop(SPIDriver *spip) {
/* If in ready state then disables the SPI clock.*/
- if (spip->spd_state == SPI_READY) {
+ if (spip->state == SPI_READY) {
/* SPI disable.*/
- spip->spd_spi->CR1 = 0;
+ spip->spi->CR1 = 0;
#if STM32_SPI_USE_SPI1
if (&SPID1 == spip) {
NVICDisableVector(DMA1_Channel2_IRQn);
NVICDisableVector(DMA1_Channel3_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_2);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_3);
RCC->APB2ENR &= ~RCC_APB2ENR_SPI1EN;
}
#endif
@@ -337,7 +272,8 @@ void spi_lld_stop(SPIDriver *spip) {
if (&SPID2 == spip) {
NVICDisableVector(DMA1_Channel4_IRQn);
NVICDisableVector(DMA1_Channel5_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_4);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_5);
RCC->APB1ENR &= ~RCC_APB1ENR_SPI2EN;
}
#endif
@@ -345,7 +281,8 @@ void spi_lld_stop(SPIDriver *spip) {
if (&SPID3 == spip) {
NVICDisableVector(DMA2_Channel1_IRQn);
NVICDisableVector(DMA2_Channel2_IRQn);
- dmaDisable(DMA2_ID);
+ dmaRelease(STM32_DMA2_ID, STM32_DMA_CHANNEL_1);
+ dmaRelease(STM32_DMA2_ID, STM32_DMA_CHANNEL_2);
RCC->APB1ENR &= ~RCC_APB1ENR_SPI3EN;
}
#endif
@@ -361,7 +298,7 @@ void spi_lld_stop(SPIDriver *spip) {
*/
void spi_lld_select(SPIDriver *spip) {
- palClearPad(spip->spd_config->spc_ssport, spip->spd_config->spc_sspad);
+ palClearPad(spip->config->ssport, spip->config->sspad);
}
/**
@@ -374,7 +311,7 @@ void spi_lld_select(SPIDriver *spip) {
*/
void spi_lld_unselect(SPIDriver *spip) {
- palSetPad(spip->spd_config->spc_ssport, spip->spd_config->spc_sspad);
+ palSetPad(spip->config->ssport, spip->config->sspad);
}
/**
@@ -390,10 +327,10 @@ void spi_lld_unselect(SPIDriver *spip) {
*/
void spi_lld_ignore(SPIDriver *spip, size_t n) {
- dmaChannelSetup(spip->spd_dmarx, n, &dummyrx,
- spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_EN);
- dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
- spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_EN);
+ dmaChannelSetup(spip->dmarx, n, &dummyrx,
+ spip->dmaccr | DMA_CCR1_TCIE | DMA_CCR1_EN);
+ dmaChannelSetup(spip->dmatx, n, &dummytx,
+ spip->dmaccr | DMA_CCR1_DIR | DMA_CCR1_EN);
}
/**
@@ -414,11 +351,11 @@ void spi_lld_ignore(SPIDriver *spip, size_t n) {
void spi_lld_exchange(SPIDriver *spip, size_t n,
const void *txbuf, void *rxbuf) {
- dmaChannelSetup(spip->spd_dmarx, n, rxbuf,
- spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC |
+ dmaChannelSetup(spip->dmarx, n, rxbuf,
+ spip->dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC |
DMA_CCR1_EN);
- dmaChannelSetup(spip->spd_dmatx, n, txbuf,
- spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
+ dmaChannelSetup(spip->dmatx, n, txbuf,
+ spip->dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
DMA_CCR1_EN);
}
@@ -437,10 +374,10 @@ void spi_lld_exchange(SPIDriver *spip, size_t n,
*/
void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
- dmaChannelSetup(spip->spd_dmarx, n, &dummyrx,
- spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_EN);
- dmaChannelSetup(spip->spd_dmatx, n, txbuf,
- spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
+ dmaChannelSetup(spip->dmarx, n, &dummyrx,
+ spip->dmaccr | DMA_CCR1_TCIE | DMA_CCR1_EN);
+ dmaChannelSetup(spip->dmatx, n, txbuf,
+ spip->dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
DMA_CCR1_EN);
}
@@ -459,11 +396,11 @@ void spi_lld_send(SPIDriver *spip, size_t n, const void *txbuf) {
*/
void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
- dmaChannelSetup(spip->spd_dmarx, n, rxbuf,
- spip->spd_dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC |
+ dmaChannelSetup(spip->dmarx, n, rxbuf,
+ spip->dmaccr | DMA_CCR1_TCIE | DMA_CCR1_MINC |
DMA_CCR1_EN);
- dmaChannelSetup(spip->spd_dmatx, n, &dummytx,
- spip->spd_dmaccr | DMA_CCR1_DIR | DMA_CCR1_EN);
+ dmaChannelSetup(spip->dmatx, n, &dummytx,
+ spip->dmaccr | DMA_CCR1_DIR | DMA_CCR1_EN);
}
/**
@@ -480,10 +417,10 @@ void spi_lld_receive(SPIDriver *spip, size_t n, void *rxbuf) {
*/
uint16_t spi_lld_polled_exchange(SPIDriver *spip, uint16_t frame) {
- spip->spd_spi->DR = frame;
- while ((spip->spd_spi->SR & SPI_SR_RXNE) == 0)
+ spip->spi->DR = frame;
+ while ((spip->spi->SR & SPI_SR_RXNE) == 0)
;
- return spip->spd_spi->DR;
+ return spip->spi->DR;
}
#endif /* HAL_USE_SPI */
diff --git a/os/hal/platforms/STM32/spi_lld.h b/os/hal/platforms/STM32/spi_lld.h
index 9e29c5d68..6f1e94096 100644
--- a/os/hal/platforms/STM32/spi_lld.h
+++ b/os/hal/platforms/STM32/spi_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -72,7 +73,7 @@
* over the TX channel.
*/
#if !defined(STM32_SPI_SPI1_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI1_DMA_PRIORITY 2
+#define STM32_SPI_SPI1_DMA_PRIORITY 1
#endif
/**
@@ -82,7 +83,7 @@
* over the TX channel.
*/
#if !defined(STM32_SPI_SPI2_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI2_DMA_PRIORITY 2
+#define STM32_SPI_SPI2_DMA_PRIORITY 1
#endif
/**
@@ -92,7 +93,7 @@
* over the TX channel.
*/
#if !defined(STM32_SPI_SPI3_DMA_PRIORITY) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI3_DMA_PRIORITY 2
+#define STM32_SPI_SPI3_DMA_PRIORITY 1
#endif
/**
@@ -117,30 +118,12 @@
#endif
/**
- * @brief SPI1 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
+ * @brief SPI DMA error hook.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
*/
-#if !defined(STM32_SPI_SPI1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI1_DMA_ERROR_HOOK() chSysHalt()
-#endif
-
-/**
- * @brief SPI2 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
- */
-#if !defined(STM32_SPI_SPI2_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI2_DMA_ERROR_HOOK() chSysHalt()
-#endif
-
-/**
- * @brief SPI3 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
- */
-#if !defined(STM32_SPI_SPI3_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_SPI_SPI3_DMA_ERROR_HOOK() chSysHalt()
+#if !defined(STM32_SPI_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_SPI_DMA_ERROR_HOOK(spip) chSysHalt()
#endif
/*===========================================================================*/
@@ -163,6 +146,10 @@
#error "SPI driver activated but no SPI peripheral assigned"
#endif
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@@ -187,20 +174,20 @@ typedef struct {
/**
* @brief Operation complete callback or @p NULL.
*/
- spicallback_t spc_endcb;
+ spicallback_t end_cb;
/* End of the mandatory fields.*/
/**
* @brief The chip select line port.
*/
- ioportid_t spc_ssport;
+ ioportid_t ssport;
/**
* @brief The chip select line pad number.
*/
- uint16_t spc_sspad;
+ uint16_t sspad;
/**
* @brief SPI initialization data.
*/
- uint16_t spc_cr1;
+ uint16_t cr1;
} SPIConfig;
/**
@@ -210,25 +197,25 @@ struct SPIDriver{
/**
* @brief Driver state.
*/
- spistate_t spd_state;
+ spistate_t state;
/**
* @brief Current configuration data.
*/
- const SPIConfig *spd_config;
+ const SPIConfig *config;
#if SPI_USE_WAIT || defined(__DOXYGEN__)
/**
* @brief Waiting thread.
*/
- Thread *spd_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 spd_mutex;
+ Mutex mutex;
#elif CH_USE_SEMAPHORES
- Semaphore spd_semaphore;
+ Semaphore semaphore;
#endif
#endif /* SPI_USE_MUTUAL_EXCLUSION */
#if defined(SPI_DRIVER_EXT_FIELDS)
@@ -238,19 +225,19 @@ struct SPIDriver{
/**
* @brief Pointer to the SPIx registers block.
*/
- SPI_TypeDef *spd_spi;
+ SPI_TypeDef *spi;
/**
* @brief Pointer to the receive DMA channel registers block.
*/
- stm32_dma_channel_t *spd_dmarx;
+ stm32_dma_channel_t *dmarx;
/**
* @brief Pointer to the transmit DMA channel registers block.
*/
- stm32_dma_channel_t *spd_dmatx;
+ stm32_dma_channel_t *dmatx;
/**
* @brief DMA priority bit mask.
*/
- uint32_t spd_dmaccr;
+ uint32_t dmaccr;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/stm32_dma.c b/os/hal/platforms/STM32/stm32_dma.c
index e25e05ad1..2232df448 100644
--- a/os/hal/platforms/STM32/stm32_dma.c
+++ b/os/hal/platforms/STM32/stm32_dma.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -22,23 +23,43 @@
* @brief STM32 DMA helper driver code.
*
* @addtogroup STM32_DMA
+ * @details DMA sharing helper driver. In the STM32 the DMA channels are a
+ * shared resource, this driver allows to allocate and free DMA
+ * channels at runtime in order to allow all the other device
+ * drivers to coordinate the access to the resource.
+ * @note The DMA ISR handlers are all declared into this module because
+ * sharing, the various device drivers can associate a callback to
+ * IRSs when allocating channels.
* @{
*/
#include "ch.h"
#include "hal.h"
+#if defined(STM32_DMA_REQUIRED) || defined(__DOXYGEN__)
+
/*===========================================================================*/
/* Driver exported variables. */
/*===========================================================================*/
/*===========================================================================*/
-/* Driver local variables. */
+/* Driver local variables and types. */
/*===========================================================================*/
-static cnt_t dmacnt1;
+/**
+ * @brief DMA ISR redirector type.
+ */
+typedef struct {
+ stm32_dmaisr_t dmaisrfunc;
+ void *dmaisrparam;
+} dma_isr_redir_t;
+
+static uint32_t dmamsk1;
+static dma_isr_redir_t dma1[7];
+
#if STM32_HAS_DMA2
-static cnt_t dmacnt2;
+static uint32_t dmamsk2;
+static dma_isr_redir_t dma2[5];
#endif
/*===========================================================================*/
@@ -49,6 +70,258 @@ static cnt_t dmacnt2;
/* Driver interrupt handlers. */
/*===========================================================================*/
+/**
+ * @brief DMA1 channel 1 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch1_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_1 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_1);
+ if (dma1[0].dmaisrfunc)
+ dma1[0].dmaisrfunc(dma1[0].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 2 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_2 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
+ if (dma1[1].dmaisrfunc)
+ dma1[1].dmaisrfunc(dma1[1].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 3 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_3 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
+ if (dma1[2].dmaisrfunc)
+ dma1[2].dmaisrfunc(dma1[2].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 4 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_4 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
+ if (dma1[3].dmaisrfunc)
+ dma1[3].dmaisrfunc(dma1[3].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 5 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_5 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
+ if (dma1[4].dmaisrfunc)
+ dma1[4].dmaisrfunc(dma1[4].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 6 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_6 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6);
+ if (dma1[5].dmaisrfunc)
+ dma1[5].dmaisrfunc(dma1[5].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA1 channel 7 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA1_Ch7_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA1->ISR >> (STM32_DMA_CHANNEL_7 * 4);
+ dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_7);
+ if (dma1[6].dmaisrfunc)
+ dma1[6].dmaisrfunc(dma1[6].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#if STM32_HAS_DMA2 || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 channel 1 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch1_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_1 * 4);
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_1);
+ if (dma2[0].dmaisrfunc)
+ dma2[0].dmaisrfunc(dma2[0].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 channel 2 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch2_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_2 * 4);
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_2);
+ if (dma2[1].dmaisrfunc)
+ dma2[1].dmaisrfunc(dma2[1].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 channel 3 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch3_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_3 * 4);
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_3);
+ if (dma2[2].dmaisrfunc)
+ dma2[2].dmaisrfunc(dma2[2].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#if defined(STM32F10X_CL) || defined(__DOXYGEN__)
+/**
+ * @brief DMA2 channel 4 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch4_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_4 * 4);
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_4);
+ if (dma2[3].dmaisrfunc)
+ dma2[3].dmaisrfunc(dma2[3].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+/**
+ * @brief DMA2 channel 5 shared interrupt handler.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch5_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_5 * 4);
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5);
+ if (dma2[4].dmaisrfunc)
+ dma2[4].dmaisrfunc(dma2[4].dmaisrparam, isr);
+
+ CH_IRQ_EPILOGUE();
+}
+
+#else /* !STM32F10X_CL */
+/**
+ * @brief DMA2 channels 4 and 5 shared interrupt handler.
+ * @note This IRQ is shared between DMA2 channels 4 and 5 so it is a
+ * bit less efficient because an extra check.
+ *
+ * @isr
+ */
+CH_IRQ_HANDLER(DMA2_Ch4_5_IRQHandler) {
+ uint32_t isr;
+
+ CH_IRQ_PROLOGUE();
+
+ /* Check on channel 4.*/
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_5 * 4);
+ if (isr & DMA_ISR_GIF1) {
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5);
+ if (dma2[3].dmaisrfunc)
+ dma2[3].dmaisrfunc(dma2[3].dmaisrparam, isr);
+ }
+
+ /* Check on channel 5.*/
+ isr = STM32_DMA2->ISR >> (STM32_DMA_CHANNEL_4 * 4);
+ if (isr & DMA_ISR_GIF1) {
+ dmaClearChannel(STM32_DMA2, STM32_DMA_CHANNEL_5);
+ if (dma2[4].dmaisrfunc)
+ dma2[4].dmaisrfunc(dma2[4].dmaisrparam, isr);
+ }
+
+ CH_IRQ_EPILOGUE();
+}
+#endif /* !STM32F10X_CL */
+#endif /* STM32_HAS_DMA2 */
+
/*===========================================================================*/
/* Driver exported functions. */
/*===========================================================================*/
@@ -61,66 +334,135 @@ static cnt_t dmacnt2;
void dmaInit(void) {
int i;
- dmacnt1 = 0;
- for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--)
+ dmamsk1 = 0;
+ for (i = STM32_DMA_CHANNEL_7; i >= STM32_DMA_CHANNEL_1; i--) {
dmaDisableChannel(STM32_DMA1, i);
+ dma1[i].dmaisrfunc = NULL;
+ }
STM32_DMA1->IFCR = 0xFFFFFFFF;
#if STM32_HAS_DMA2
- dmacnt2 = 0;
- for (i = STM32_DMA_CHANNEL_5; i >= STM32_DMA_CHANNEL_1; i--)
+ dmamsk2 = 0;
+ for (i = STM32_DMA_CHANNEL_5; i >= STM32_DMA_CHANNEL_1; i--) {
dmaDisableChannel(STM32_DMA2, i);
+ dma2[i].dmaisrfunc = NULL;
+ }
STM32_DMA1->IFCR = 0xFFFFFFFF;
#endif
}
/**
- * @brief Enables the specified DMA controller clock.
+ * @brief Allocates a DMA channel.
+ * @details The channel is allocated and, if required, the DMA clock enabled.
+ * Trying to allocate a channel already allocated is an illegal
+ * operation and is trapped if assertions are enabled.
+ * @pre The channel must not be already in use.
+ * @post The channel is allocated and the default ISR handler redirected
+ * to the specified function.
+ * @post The channel must be freed using @p dmaRelease() before it can
+ * be reused with another peripheral.
+ * @note This function can be invoked in both ISR or thread context.
*
- * @param[in] dma the DMA controller id
+ * @param[in] dma DMA controller id
+ * @param[in] channel requested channel id
+ * @param[in] func handling function pointer, can be @p NULL
+ * @param[in] param a parameter to be passed to the handling function
+ * @return The operation status.
+ * @retval FALSE operation successfully allocated.
+ * @retval TRUE the channel was already in use.
*
- * @api
+ * @special
*/
-void dmaEnable(uint32_t dma) {
+void dmaAllocate(uint32_t dma, uint32_t channel,
+ stm32_dmaisr_t func, void *param) {
+ chDbgCheck(func != NULL, "dmaAllocate");
+
+#if STM32_HAS_DMA2
switch (dma) {
- case DMA1_ID:
- if (dmacnt1++ == 0) {
+ case STM32_DMA1_ID:
+#else
+ (void)dma;
+#endif
+ /* Check if the channel is already taken.*/
+ chDbgAssert((dmamsk1 & (1 << channel)) == 0,
+ "dmaAllocate(), #1", "already allocated");
+
+ /* If the DMA unit was idle then the clock is enabled.*/
+ if (dmamsk1 == 0) {
RCC->AHBENR |= RCC_AHBENR_DMA1EN;
DMA1->IFCR = 0x0FFFFFFF;
}
- break;
+
+ dmamsk1 |= 1 << channel;
+ dma1[channel].dmaisrfunc = func;
+ dma1[channel].dmaisrparam = param;
#if STM32_HAS_DMA2
- case DMA2_ID:
- if (dmacnt2++ == 0) {
+ break;
+ case STM32_DMA2_ID:
+ /* Check if the channel is already taken.*/
+ chDbgAssert((dmamsk2 & (1 << channel)) == 0,
+ "dmaAllocate(), #2", "already allocated");
+
+ /* If the DMA unit was idle then the clock is enabled.*/
+ if (dmamsk2 == 0) {
RCC->AHBENR |= RCC_AHBENR_DMA2EN;
DMA2->IFCR = 0x0FFFFFFF;
}
+
+ dmamsk2 |= 1 << channel;
+ dma2[channel].dmaisrfunc = func;
+ dma2[channel].dmaisrparam = param;
break;
-#endif
}
+#endif
}
/**
- * @brief Disables the specified DMA controller clock.
+ * @brief Releases a DMA channel.
+ * @details The channel is freed and, if required, the DMA clock disabled.
+ * Trying to release a unallocated channel is an illegal operation
+ * and is trapped if assertions are enabled.
+ * @pre The channel must have been allocated using @p dmaRequest().
+ * @post The channel is again available.
+ * @note This function can be invoked in both ISR or thread context.
*
- * @param[in] dma the DMA controller id
+ * @param[in] dma DMA controller id
+ * @param[in] channel requested channel id
*
- * @api
+ * @special
*/
-void dmaDisable(uint32_t dma) {
+void dmaRelease(uint32_t dma, uint32_t channel) {
+#if STM32_HAS_DMA2
switch (dma) {
- case DMA1_ID:
- if (--dmacnt1 == 0)
+ case STM32_DMA1_ID:
+#else
+ (void)dma;
+#endif
+ /* Check if the channel is not taken.*/
+ chDbgAssert((dmamsk1 & (1 << channel)) != 0,
+ "dmaRelease(), #1", "not allocated");
+
+ dma1[channel].dmaisrfunc = NULL;
+ dmamsk1 &= ~(1 << channel);
+ if (dmamsk1 == 0)
RCC->AHBENR &= ~RCC_AHBENR_DMA1EN;
- break;
#if STM32_HAS_DMA2
- case DMA2_ID:
- if (--dmacnt2 == 0)
+ break;
+ case STM32_DMA2_ID:
+ /* Check if the channel is not taken.*/
+ chDbgAssert((dmamsk2 & (1 << channel)) != 0,
+ "dmaRelease(), #2", "not allocated");
+
+ dma2[channel].dmaisrfunc = NULL;
+ dmamsk2 &= ~(1 << channel);
+ if (dmamsk2 == 0)
RCC->AHBENR &= ~RCC_AHBENR_DMA2EN;
break;
-#endif
}
+#endif
}
+#endif /* STM32_DMA_REQUIRED */
+
/** @} */
diff --git a/os/hal/platforms/STM32/stm32_dma.h b/os/hal/platforms/STM32/stm32_dma.h
index 806f79c56..66a2f8c69 100644
--- a/os/hal/platforms/STM32/stm32_dma.h
+++ b/os/hal/platforms/STM32/stm32_dma.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -35,11 +36,11 @@
/*===========================================================================*/
/** @brief DMA1 identifier.*/
-#define DMA1_ID 0
+#define STM32_DMA1_ID 0
/** @brief DMA2 identifier.*/
#if STM32_HAS_DMA2 || defined(__DOXYGEN__)
-#define DMA2_ID 1
+#define STM32_DMA2_ID 1
#endif
/*===========================================================================*/
@@ -55,7 +56,7 @@
/*===========================================================================*/
/**
- * @brief STM32 DMA channel memory structure.
+ * @brief STM32 DMA channel memory structure type.
*/
typedef struct {
volatile uint32_t CCR;
@@ -66,7 +67,7 @@ typedef struct {
} stm32_dma_channel_t;
/**
- * @brief STM32 DMA subsystem memory structure.
+ * @brief STM32 DMA subsystem memory structure type.
* @note This structure has been redefined here because it is convenient to
* have the channels organized as an array, the ST header does not
* do that.
@@ -77,6 +78,14 @@ typedef struct {
stm32_dma_channel_t channels[7];
} stm32_dma_t;
+/**
+ * @brief STM32 DMA ISR function type.
+ *
+ * @param[in] p parameter for the registered function
+ * @param[in] flags pre-shifted content of the ISR register
+ */
+typedef void (*stm32_dmaisr_t)(void *p, uint32_t flags);
+
/*===========================================================================*/
/* Driver macros. */
/*===========================================================================*/
@@ -127,11 +136,12 @@ typedef struct {
/**
* @brief Associates a peripheral data register to a DMA channel.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
* @param[in] cpar value to be written in the CPAR register
*
- * @api
+ * @special
*/
#define dmaChannelSetPeripheral(dmachp, cpar) { \
(dmachp)->CPAR = (uint32_t)(cpar); \
@@ -142,13 +152,14 @@ typedef struct {
* @note This macro does not change the CPAR register because that register
* value does not change frequently, it usually points to a peripheral
* data register.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
* @param[in] cndtr value to be written in the CNDTR register
* @param[in] cmar value to be written in the CMAR register
* @param[in] ccr value to be written in the CCR register
*
- * @api
+ * @special
*/
#define dmaChannelSetup(dmachp, cndtr, cmar, ccr) { \
(dmachp)->CNDTR = (uint32_t)(cndtr); \
@@ -158,10 +169,11 @@ typedef struct {
/**
* @brief DMA channel enable by channel pointer.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
*
- * @api
+ * @special
*/
#define dmaChannelEnable(dmachp) { \
(dmachp)->CCR |= DMA_CCR1_EN; \
@@ -170,10 +182,11 @@ typedef struct {
/**
* @brief DMA channel disable by channel pointer.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmachp dmachp to a stm32_dma_channel_t structure
*
- * @api
+ * @special
*/
#define dmaChannelDisable(dmachp) { \
(dmachp)->CCR = 0; \
@@ -186,6 +199,7 @@ typedef struct {
* data register.
* @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmap pointer to a stm32_dma_t structure
* @param[in] ch channel number
@@ -193,7 +207,7 @@ typedef struct {
* @param[in] cmar value to be written in the CMAR register
* @param[in] ccr value to be written in the CCR register
*
- * @api
+ * @special
*/
#define dmaSetupChannel(dmap, ch, cndtr, cmar, ccr) { \
dmaChannelSetup(&(dmap)->channels[ch], (cndtr), (cmar), (ccr)); \
@@ -203,11 +217,12 @@ typedef struct {
* @brief DMA channel enable by channel ID.
* @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmap pointer to a stm32_dma_t structure
* @param[in] ch channel number
*
- * @api
+ * @special
*/
#define dmaEnableChannel(dmap, ch) { \
dmaChannelEnable(&(dmap)->channels[ch]); \
@@ -217,11 +232,12 @@ typedef struct {
* @brief DMA channel disable by channel ID.
* @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmap pointer to a stm32_dma_t structure
* @param[in] ch channel number
*
- * @api
+ * @special
*/
#define dmaDisableChannel(dmap, ch) { \
dmaChannelDisable(&(dmap)->channels[ch]); \
@@ -233,11 +249,12 @@ typedef struct {
* withdraw all the pending interrupt bits from the ISR register.
* @note Channels are numbered from 0 to 6, use the appropriate macro
* as parameter.
+ * @note This function can be invoked in both ISR or thread context.
*
* @param[in] dmap pointer to a stm32_dma_t structure
* @param[in] ch channel number
*
- * @api
+ * @special
*/
#define dmaClearChannel(dmap, ch){ \
(dmap)->IFCR = 1 << ((ch) * 4); \
@@ -251,8 +268,9 @@ typedef struct {
extern "C" {
#endif
void dmaInit(void);
- void dmaEnable(uint32_t dma);
- void dmaDisable(uint32_t dma);
+ void dmaAllocate(uint32_t dma, uint32_t channel,
+ stm32_dmaisr_t func, void *param);
+ void dmaRelease(uint32_t dma, uint32_t channel);
#ifdef __cplusplus
}
#endif
diff --git a/os/hal/platforms/STM32/stm32_usb.h b/os/hal/platforms/STM32/stm32_usb.h
index 8c04ba85f..51e7510c4 100644
--- a/os/hal/platforms/STM32/stm32_usb.h
+++ b/os/hal/platforms/STM32/stm32_usb.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -108,11 +109,16 @@ typedef struct {
#define STM32_USB ((stm32_usb_t *)STM32_USB_BASE)
/**
- * @brief Pointer to the USB RAM.
+ * @brief Pointer to the USB RAM.
*/
#define STM32_USBRAM ((uint32_t *)STM32_USBRAM_BASE)
/**
+ * @brief Size of the dedicated packet memory.
+ */
+#define USB_PMA_SIZE 512
+
+/**
* @brief Mask of all the toggling bits in the EPR register.
*/
#define EPR_TOGGLE_MASK (EPR_STAT_TX_MASK | EPR_DTOG_TX | \
diff --git a/os/hal/platforms/STM32/stm32f10x.h b/os/hal/platforms/STM32/stm32f10x.h
index a6f71cbdb..a187f0a84 100644
--- a/os/hal/platforms/STM32/stm32f10x.h
+++ b/os/hal/platforms/STM32/stm32f10x.h
@@ -2,14 +2,15 @@
******************************************************************************
* @file stm32f10x.h
* @author MCD Application Team
- * @version V3.3.0
- * @date 04/16/2010
- * @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File.
- * This file contains all the peripheral register's definitions, bits
- * definitions and memory mapping for STM32F10x Connectivity line, High
- * density, Medium density, Medium density Value line, Low density
- * and Low density Value line and XL-density devices.
- ******************************************************************************
+ * @version V3.4.0
+ * @date 10/15/2010
+ * @brief CMSIS Cortex-M3 Device Peripheral Access Layer Header File.
+ * This file contains all the peripheral register's definitions, bits
+ * definitions and memory mapping for STM32F10x Connectivity line,
+ * High density, High density value line, Medium density,
+ * Medium density Value line, Low density, Low density Value line
+ * and XL-density devices.
+ ******************************************************************************
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
@@ -29,77 +30,84 @@
/** @addtogroup stm32f10x
* @{
*/
-
+
#ifndef __STM32F10x_H
#define __STM32F10x_H
#ifdef __cplusplus
extern "C" {
-#endif
-
+#endif
+
/** @addtogroup Library_configuration_section
* @{
*/
-
+
/* Uncomment the line below according to the target STM32 device used in your
- application
+ application
*/
-#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
+#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
/* #define STM32F10X_LD */ /*!< STM32F10X_LD: STM32 Low density devices */
- /* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
+ /* #define STM32F10X_LD_VL */ /*!< STM32F10X_LD_VL: STM32 Low density Value Line devices */
/* #define STM32F10X_MD */ /*!< STM32F10X_MD: STM32 Medium density devices */
- /* #define STM32F10X_MD_VL */ /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */
+ /* #define STM32F10X_MD_VL */ /*!< STM32F10X_MD_VL: STM32 Medium density Value Line devices */
/* #define STM32F10X_HD */ /*!< STM32F10X_HD: STM32 High density devices */
- #define STM32F10X_XL /*!< STM32F10X_XL: STM32 XL-density devices */
+ /* #define STM32F10X_HD_VL */ /*!< STM32F10X_HD_VL: STM32 High density value line devices */
+ /* #define STM32F10X_XL */ /*!< STM32F10X_XL: STM32 XL-density devices */
/* #define STM32F10X_CL */ /*!< STM32F10X_CL: STM32 Connectivity line devices */
#endif
/* Tip: To avoid modifying this file each time you need to switch between these
devices, you can define the device in your toolchain compiler preprocessor.
- - Low density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
+ - Low-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
where the Flash memory density ranges between 16 and 32 Kbytes.
- Low-density value line devices are STM32F100xx microcontrollers where the Flash
memory density ranges between 16 and 32 Kbytes.
- - Medium density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
+ - Medium-density devices are STM32F101xx, STM32F102xx and STM32F103xx microcontrollers
where the Flash memory density ranges between 64 and 128 Kbytes.
- - Medium-density value line devices are STM32F100xx microcontrollers where the
- Flash memory density ranges between 64 and 128 Kbytes.
- - High density devices are STM32F101xx and STM32F103xx microcontrollers where
+ - Medium-density value line devices are STM32F100xx microcontrollers where the
+ Flash memory density ranges between 64 and 128 Kbytes.
+ - High-density devices are STM32F101xx and STM32F103xx microcontrollers where
the Flash memory density ranges between 256 and 512 Kbytes.
+ - High-density value line devices are STM32F100xx microcontrollers where the
+ Flash memory density ranges between 256 and 512 Kbytes.
- XL-density devices are STM32F101xx and STM32F103xx microcontrollers where
the Flash memory density ranges between 512 and 1024 Kbytes.
- Connectivity line devices are STM32F105xx and STM32F107xx microcontrollers.
*/
+#if !defined (STM32F10X_LD) && !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD) && !defined (STM32F10X_HD_VL) && !defined (STM32F10X_XL) && !defined (STM32F10X_CL)
+ #error "Please select first the target STM32F10x device used in your application (in stm32f10x.h file)"
+#endif
+
#if !defined USE_STDPERIPH_DRIVER
/**
* @brief Comment the line below if you will not use the peripherals drivers.
- In this case, these drivers will not be included and the application code will
- be based on direct access to peripherals registers
+ In this case, these drivers will not be included and the application code will
+ be based on direct access to peripherals registers
*/
/*#define USE_STDPERIPH_DRIVER*/
#endif
/**
* @brief In the following line adjust the value of External High Speed oscillator (HSE)
- used in your application
-
+ used in your application
+
Tip: To avoid modifying this file each time you need to use different HSE, you
can define the HSE value in your toolchain compiler preprocessor.
- */
+ */
#if !defined HSE_VALUE
- #ifdef STM32F10X_CL
+ #ifdef STM32F10X_CL
#define HSE_VALUE ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
- #else
+ #else
#define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */
#endif /* STM32F10X_CL */
#endif /* HSE_VALUE */
/**
- * @brief In the following line adjust the External High Speed oscillator (HSE) Startup
- Timeout value
+ * @brief In the following line adjust the External High Speed oscillator (HSE) Startup
+ Timeout value
*/
#define HSE_STARTUP_TIMEOUT ((uint16_t)0x0500) /*!< Time out for HSE start up */
@@ -109,7 +117,7 @@
* @brief STM32F10x Standard Peripheral Library version number
*/
#define __STM32F10X_STDPERIPH_VERSION_MAIN (0x03) /*!< [31:16] STM32F10x Standard Peripheral Library main version */
-#define __STM32F10X_STDPERIPH_VERSION_SUB1 (0x03) /*!< [15:8] STM32F10x Standard Peripheral Library sub1 version */
+#define __STM32F10X_STDPERIPH_VERSION_SUB1 (0x04) /*!< [15:8] STM32F10x Standard Peripheral Library sub1 version */
#define __STM32F10X_STDPERIPH_VERSION_SUB2 (0x00) /*!< [7:0] STM32F10x Standard Peripheral Library sub2 version */
#define __STM32F10X_STDPERIPH_VERSION ((__STM32F10X_STDPERIPH_VERSION_MAIN << 16)\
| (__STM32F10X_STDPERIPH_VERSION_SUB1 << 8)\
@@ -124,7 +132,7 @@
*/
/**
- * @brief Configuration of the Cortex-M3 Processor and Core Peripherals
+ * @brief Configuration of the Cortex-M3 Processor and Core Peripherals
*/
#ifdef STM32F10X_XL
#define __MPU_PRESENT 1 /*!< STM32 XL-density devices provide an MPU */
@@ -135,8 +143,8 @@
#define __Vendor_SysTickConfig 0 /*!< Set to 1 if different SysTick Config is used */
/**
- * @brief STM32F10x Interrupt Number Definition, according to the selected device
- * in @ref Library_configuration_section
+ * @brief STM32F10x Interrupt Number Definition, according to the selected device
+ * in @ref Library_configuration_section
*/
typedef enum IRQn
{
@@ -190,8 +198,8 @@ typedef enum IRQn
USART2_IRQn = 38, /*!< USART2 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
- USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
-#endif /* STM32F10X_LD */
+ USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
+#endif /* STM32F10X_LD */
#ifdef STM32F10X_LD_VL
ADC1_IRQn = 18, /*!< ADC1 global Interrupt */
@@ -209,9 +217,9 @@ typedef enum IRQn
USART2_IRQn = 38, /*!< USART2 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
- CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
- TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
- TIM7_IRQn = 55 /*!< TIM7 Interrupt */
+ CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
+ TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
+ TIM7_IRQn = 55 /*!< TIM7 Interrupt */
#endif /* STM32F10X_LD_VL */
#ifdef STM32F10X_MD
@@ -239,8 +247,8 @@ typedef enum IRQn
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
- USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
-#endif /* STM32F10X_MD */
+ USBWakeUp_IRQn = 42 /*!< USB Device WakeUp from suspend through EXTI Line Interrupt */
+#endif /* STM32F10X_MD */
#ifdef STM32F10X_MD_VL
ADC1_IRQn = 18, /*!< ADC1 global Interrupt */
@@ -263,9 +271,9 @@ typedef enum IRQn
USART3_IRQn = 39, /*!< USART3 global Interrupt */
EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
- CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
- TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
- TIM7_IRQn = 55 /*!< TIM7 Interrupt */
+ CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
+ TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
+ TIM7_IRQn = 55 /*!< TIM7 Interrupt */
#endif /* STM32F10X_MD_VL */
#ifdef STM32F10X_HD
@@ -311,7 +319,48 @@ typedef enum IRQn
DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */
DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */
DMA2_Channel4_5_IRQn = 59 /*!< DMA2 Channel 4 and Channel 5 global Interrupt */
-#endif /* STM32F10X_HD */
+#endif /* STM32F10X_HD */
+
+#ifdef STM32F10X_HD_VL
+ ADC1_IRQn = 18, /*!< ADC1 global Interrupt */
+ EXTI9_5_IRQn = 23, /*!< External Line[9:5] Interrupts */
+ TIM1_BRK_TIM15_IRQn = 24, /*!< TIM1 Break and TIM15 Interrupts */
+ TIM1_UP_TIM16_IRQn = 25, /*!< TIM1 Update and TIM16 Interrupts */
+ TIM1_TRG_COM_TIM17_IRQn = 26, /*!< TIM1 Trigger and Commutation and TIM17 Interrupt */
+ TIM1_CC_IRQn = 27, /*!< TIM1 Capture Compare Interrupt */
+ TIM2_IRQn = 28, /*!< TIM2 global Interrupt */
+ TIM3_IRQn = 29, /*!< TIM3 global Interrupt */
+ TIM4_IRQn = 30, /*!< TIM4 global Interrupt */
+ I2C1_EV_IRQn = 31, /*!< I2C1 Event Interrupt */
+ I2C1_ER_IRQn = 32, /*!< I2C1 Error Interrupt */
+ I2C2_EV_IRQn = 33, /*!< I2C2 Event Interrupt */
+ I2C2_ER_IRQn = 34, /*!< I2C2 Error Interrupt */
+ SPI1_IRQn = 35, /*!< SPI1 global Interrupt */
+ SPI2_IRQn = 36, /*!< SPI2 global Interrupt */
+ USART1_IRQn = 37, /*!< USART1 global Interrupt */
+ USART2_IRQn = 38, /*!< USART2 global Interrupt */
+ USART3_IRQn = 39, /*!< USART3 global Interrupt */
+ EXTI15_10_IRQn = 40, /*!< External Line[15:10] Interrupts */
+ RTCAlarm_IRQn = 41, /*!< RTC Alarm through EXTI Line Interrupt */
+ CEC_IRQn = 42, /*!< HDMI-CEC Interrupt */
+ TIM12_IRQn = 43, /*!< TIM12 global Interrupt */
+ TIM13_IRQn = 44, /*!< TIM13 global Interrupt */
+ TIM14_IRQn = 45, /*!< TIM14 global Interrupt */
+ FSMC_IRQn = 48, /*!< FSMC global Interrupt */
+ TIM5_IRQn = 50, /*!< TIM5 global Interrupt */
+ SPI3_IRQn = 51, /*!< SPI3 global Interrupt */
+ UART4_IRQn = 52, /*!< UART4 global Interrupt */
+ UART5_IRQn = 53, /*!< UART5 global Interrupt */
+ TIM6_DAC_IRQn = 54, /*!< TIM6 and DAC underrun Interrupt */
+ TIM7_IRQn = 55, /*!< TIM7 Interrupt */
+ DMA2_Channel1_IRQn = 56, /*!< DMA2 Channel 1 global Interrupt */
+ DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */
+ DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */
+ DMA2_Channel4_5_IRQn = 59, /*!< DMA2 Channel 4 and Channel 5 global Interrupt */
+ DMA2_Channel5_IRQn = 60 /*!< DMA2 Channel 5 global Interrupt (DMA2 Channel 5 is
+ mapped at postion 60 only if the MISC_REMAP bit in
+ the AFIO_MAPR2 register is set) */
+#endif /* STM32F10X_HD_VL */
#ifdef STM32F10X_XL
ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */
@@ -356,7 +405,7 @@ typedef enum IRQn
DMA2_Channel2_IRQn = 57, /*!< DMA2 Channel 2 global Interrupt */
DMA2_Channel3_IRQn = 58, /*!< DMA2 Channel 3 global Interrupt */
DMA2_Channel4_5_IRQn = 59 /*!< DMA2 Channel 4 and Channel 5 global Interrupt */
-#endif /* STM32F10X_XL */
+#endif /* STM32F10X_XL */
#ifdef STM32F10X_CL
ADC1_2_IRQn = 18, /*!< ADC1 and ADC2 global Interrupt */
@@ -402,7 +451,7 @@ typedef enum IRQn
CAN2_RX1_IRQn = 65, /*!< CAN2 RX1 Interrupt */
CAN2_SCE_IRQn = 66, /*!< CAN2 SCE Interrupt */
OTG_FS_IRQn = 67 /*!< USB OTG FS global Interrupt */
-#endif /* STM32F10X_CL */
+#endif /* STM32F10X_CL */
} IRQn_Type;
/**
@@ -415,7 +464,7 @@ typedef enum IRQn
/** @addtogroup Exported_types
* @{
- */
+ */
/*!< STM32F10x Standard Peripheral Library old types (maintained for legacy purpose) */
typedef int32_t s32;
@@ -450,10 +499,6 @@ typedef __I uint32_t vuc32; /*!< Read Only */
typedef __I uint16_t vuc16; /*!< Read Only */
typedef __I uint8_t vuc8; /*!< Read Only */
-#ifndef __cplusplus
-typedef enum {FALSE = 0, TRUE = !FALSE} bool;
-#endif
-
typedef enum {RESET = 0, SET = !RESET} FlagStatus, ITStatus;
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;
@@ -471,10 +516,10 @@ typedef enum {ERROR = 0, SUCCESS = !ERROR} ErrorStatus;
/** @addtogroup Peripheral_registers_structures
* @{
- */
+ */
-/**
- * @brief Analog to Digital Converter
+/**
+ * @brief Analog to Digital Converter
*/
typedef struct
@@ -501,8 +546,8 @@ typedef struct
__IO uint32_t DR;
} ADC_TypeDef;
-/**
- * @brief Backup Registers
+/**
+ * @brief Backup Registers
*/
typedef struct
@@ -527,7 +572,7 @@ typedef struct
__IO uint16_t DR9;
uint16_t RESERVED9;
__IO uint16_t DR10;
- uint16_t RESERVED10;
+ uint16_t RESERVED10;
__IO uint16_t RTCCR;
uint16_t RESERVED11;
__IO uint16_t CR;
@@ -573,7 +618,7 @@ typedef struct
__IO uint16_t DR29;
uint16_t RESERVED32;
__IO uint16_t DR30;
- uint16_t RESERVED33;
+ uint16_t RESERVED33;
__IO uint16_t DR31;
uint16_t RESERVED34;
__IO uint16_t DR32;
@@ -597,11 +642,11 @@ typedef struct
__IO uint16_t DR41;
uint16_t RESERVED44;
__IO uint16_t DR42;
- uint16_t RESERVED45;
+ uint16_t RESERVED45;
} BKP_TypeDef;
-
-/**
- * @brief Controller Area Network TxMailBox
+
+/**
+ * @brief Controller Area Network TxMailBox
*/
typedef struct
@@ -612,10 +657,10 @@ typedef struct
__IO uint32_t TDHR;
} CAN_TxMailBox_TypeDef;
-/**
- * @brief Controller Area Network FIFOMailBox
+/**
+ * @brief Controller Area Network FIFOMailBox
*/
-
+
typedef struct
{
__IO uint32_t RIR;
@@ -624,20 +669,20 @@ typedef struct
__IO uint32_t RDHR;
} CAN_FIFOMailBox_TypeDef;
-/**
- * @brief Controller Area Network FilterRegister
+/**
+ * @brief Controller Area Network FilterRegister
*/
-
+
typedef struct
{
__IO uint32_t FR1;
__IO uint32_t FR2;
} CAN_FilterRegister_TypeDef;
-/**
- * @brief Controller Area Network
+/**
+ * @brief Controller Area Network
*/
-
+
typedef struct
{
__IO uint32_t MCR;
@@ -665,10 +710,10 @@ typedef struct
CAN_FilterRegister_TypeDef sFilterRegister[14];
#else
CAN_FilterRegister_TypeDef sFilterRegister[28];
-#endif /* STM32F10X_CL */
+#endif /* STM32F10X_CL */
} CAN_TypeDef;
-/**
+/**
* @brief Consumer Electronics Control (CEC)
*/
typedef struct
@@ -679,11 +724,11 @@ typedef struct
__IO uint32_t ESR;
__IO uint32_t CSR;
__IO uint32_t TXD;
- __IO uint32_t RXD;
+ __IO uint32_t RXD;
} CEC_TypeDef;
-/**
- * @brief CRC calculation unit
+/**
+ * @brief CRC calculation unit
*/
typedef struct
@@ -695,7 +740,7 @@ typedef struct
__IO uint32_t CR;
} CRC_TypeDef;
-/**
+/**
* @brief Digital to Analog Converter
*/
@@ -714,22 +759,22 @@ typedef struct
__IO uint32_t DHR8RD;
__IO uint32_t DOR1;
__IO uint32_t DOR2;
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
__IO uint32_t SR;
#endif
} DAC_TypeDef;
-/**
+/**
* @brief Debug MCU
*/
typedef struct
{
__IO uint32_t IDCODE;
- __IO uint32_t CR;
+ __IO uint32_t CR;
}DBGMCU_TypeDef;
-/**
+/**
* @brief DMA Controller
*/
@@ -747,7 +792,7 @@ typedef struct
__IO uint32_t IFCR;
} DMA_TypeDef;
-/**
+/**
* @brief Ethernet MAC
*/
@@ -818,7 +863,7 @@ typedef struct
__IO uint32_t DMACHRBAR;
} ETH_TypeDef;
-/**
+/**
* @brief External Interrupt/Event Controller
*/
@@ -832,7 +877,7 @@ typedef struct
__IO uint32_t PR;
} EXTI_TypeDef;
-/**
+/**
* @brief FLASH Registers
*/
@@ -848,19 +893,19 @@ typedef struct
__IO uint32_t OBR;
__IO uint32_t WRPR;
#ifdef STM32F10X_XL
- uint32_t RESERVED1[8];
+ uint32_t RESERVED1[8];
__IO uint32_t KEYR2;
- uint32_t RESERVED2;
+ uint32_t RESERVED2;
__IO uint32_t SR2;
__IO uint32_t CR2;
- __IO uint32_t AR2;
-#endif /* STM32F10X_XL */
+ __IO uint32_t AR2;
+#endif /* STM32F10X_XL */
} FLASH_TypeDef;
-/**
+/**
* @brief Option Bytes Registers
*/
-
+
typedef struct
{
__IO uint16_t RDP;
@@ -873,66 +918,66 @@ typedef struct
__IO uint16_t WRP3;
} OB_TypeDef;
-/**
+/**
* @brief Flexible Static Memory Controller
*/
typedef struct
{
- __IO uint32_t BTCR[8];
-} FSMC_Bank1_TypeDef;
+ __IO uint32_t BTCR[8];
+} FSMC_Bank1_TypeDef;
-/**
+/**
* @brief Flexible Static Memory Controller Bank1E
*/
-
+
typedef struct
{
__IO uint32_t BWTR[7];
} FSMC_Bank1E_TypeDef;
-/**
+/**
* @brief Flexible Static Memory Controller Bank2
*/
-
+
typedef struct
{
__IO uint32_t PCR2;
__IO uint32_t SR2;
__IO uint32_t PMEM2;
__IO uint32_t PATT2;
- uint32_t RESERVED0;
- __IO uint32_t ECCR2;
-} FSMC_Bank2_TypeDef;
+ uint32_t RESERVED0;
+ __IO uint32_t ECCR2;
+} FSMC_Bank2_TypeDef;
-/**
+/**
* @brief Flexible Static Memory Controller Bank3
*/
-
+
typedef struct
{
__IO uint32_t PCR3;
__IO uint32_t SR3;
__IO uint32_t PMEM3;
__IO uint32_t PATT3;
- uint32_t RESERVED0;
- __IO uint32_t ECCR3;
-} FSMC_Bank3_TypeDef;
+ uint32_t RESERVED0;
+ __IO uint32_t ECCR3;
+} FSMC_Bank3_TypeDef;
-/**
+/**
* @brief Flexible Static Memory Controller Bank4
*/
-
+
typedef struct
{
__IO uint32_t PCR4;
__IO uint32_t SR4;
__IO uint32_t PMEM4;
__IO uint32_t PATT4;
- __IO uint32_t PIO4;
-} FSMC_Bank4_TypeDef;
+ __IO uint32_t PIO4;
+} FSMC_Bank4_TypeDef;
-/**
+/**
* @brief General Purpose I/O
*/
@@ -947,7 +992,7 @@ typedef struct
__IO uint32_t LCKR;
} GPIO_TypeDef;
-/**
+/**
* @brief Alternate Function I/O
*/
@@ -957,9 +1002,9 @@ typedef struct
__IO uint32_t MAPR;
__IO uint32_t EXTICR[4];
uint32_t RESERVED0;
- __IO uint32_t MAPR2;
+ __IO uint32_t MAPR2;
} AFIO_TypeDef;
-/**
+/**
* @brief Inter-integrated Circuit Interface
*/
@@ -985,7 +1030,7 @@ typedef struct
uint16_t RESERVED8;
} I2C_TypeDef;
-/**
+/**
* @brief Independent WATCHDOG
*/
@@ -997,7 +1042,7 @@ typedef struct
__IO uint32_t SR;
} IWDG_TypeDef;
-/**
+/**
* @brief Power Control
*/
@@ -1007,7 +1052,7 @@ typedef struct
__IO uint32_t CSR;
} PWR_TypeDef;
-/**
+/**
* @brief Reset and Clock Control
*/
@@ -1024,18 +1069,18 @@ typedef struct
__IO uint32_t BDCR;
__IO uint32_t CSR;
-#ifdef STM32F10X_CL
+#ifdef STM32F10X_CL
__IO uint32_t AHBRSTR;
__IO uint32_t CFGR2;
-#endif /* STM32F10X_CL */
+#endif /* STM32F10X_CL */
-#if defined STM32F10X_LD_VL || defined STM32F10X_MD_VL
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
uint32_t RESERVED0;
__IO uint32_t CFGR2;
-#endif /* STM32F10X_LD_VL || STM32F10X_MD_VL */
+#endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */
} RCC_TypeDef;
-/**
+/**
* @brief Real-Time Clock
*/
@@ -1063,7 +1108,7 @@ typedef struct
uint16_t RESERVED9;
} RTC_TypeDef;
-/**
+/**
* @brief SD host Interface
*/
@@ -1091,7 +1136,7 @@ typedef struct
__IO uint32_t FIFO;
} SDIO_TypeDef;
-/**
+/**
* @brief Serial Peripheral Interface
*/
@@ -1114,10 +1159,10 @@ typedef struct
__IO uint16_t I2SCFGR;
uint16_t RESERVED7;
__IO uint16_t I2SPR;
- uint16_t RESERVED8;
+ uint16_t RESERVED8;
} SPI_TypeDef;
-/**
+/**
* @brief TIM
*/
@@ -1165,10 +1210,10 @@ typedef struct
uint16_t RESERVED19;
} TIM_TypeDef;
-/**
+/**
* @brief Universal Synchronous Asynchronous Receiver Transmitter
*/
-
+
typedef struct
{
__IO uint16_t SR;
@@ -1187,7 +1232,7 @@ typedef struct
uint16_t RESERVED6;
} USART_TypeDef;
-/**
+/**
* @brief Window WATCHDOG
*/
@@ -1201,16 +1246,18 @@ typedef struct
/**
* @}
*/
-
+
/** @addtogroup Peripheral_memory_map
* @{
*/
-#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the alias region */
-#define SRAM_BB_BASE ((uint32_t)0x22000000) /*!< SRAM base address in the alias region */
-#define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the bit-band region */
-#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the bit-band region */
+#define FLASH_BASE ((uint32_t)0x08000000) /*!< FLASH base address in the alias region */
+#define SRAM_BASE ((uint32_t)0x20000000) /*!< SRAM base address in the alias region */
+#define PERIPH_BASE ((uint32_t)0x40000000) /*!< Peripheral base address in the alias region */
+
+#define SRAM_BB_BASE ((uint32_t)0x22000000) /*!< SRAM base address in the bit-band region */
+#define PERIPH_BB_BASE ((uint32_t)0x42000000) /*!< Peripheral base address in the bit-band region */
#define FSMC_R_BASE ((uint32_t)0xA0000000) /*!< FSMC registers base address */
@@ -1308,10 +1355,10 @@ typedef struct
/**
* @}
*/
-
+
/** @addtogroup Peripheral_declaration
* @{
- */
+ */
#define TIM2 ((TIM_TypeDef *) TIM2_BASE)
#define TIM3 ((TIM_TypeDef *) TIM3_BASE)
@@ -1379,7 +1426,7 @@ typedef struct
#define RCC ((RCC_TypeDef *) RCC_BASE)
#define CRC ((CRC_TypeDef *) CRC_BASE)
#define FLASH ((FLASH_TypeDef *) FLASH_R_BASE)
-#define OB ((OB_TypeDef *) OB_BASE)
+#define OB ((OB_TypeDef *) OB_BASE)
#define ETH ((ETH_TypeDef *) ETH_BASE)
#define FSMC_Bank1 ((FSMC_Bank1_TypeDef *) FSMC_Bank1_R_BASE)
#define FSMC_Bank1E ((FSMC_Bank1E_TypeDef *) FSMC_Bank1E_R_BASE)
@@ -1395,11 +1442,11 @@ typedef struct
/** @addtogroup Exported_constants
* @{
*/
-
+
/** @addtogroup Peripheral_Registers_Bits_Definition
* @{
*/
-
+
/******************************************************************************/
/* Peripheral Registers_Bits_Definition */
/******************************************************************************/
@@ -1727,9 +1774,9 @@ typedef struct
#define RCC_CFGR_PLLMULL8 ((uint32_t)0x00180000) /*!< PLL input clock * 8 */
#define RCC_CFGR_PLLMULL9 ((uint32_t)0x001C0000) /*!< PLL input clock * 9 */
#define RCC_CFGR_PLLMULL6_5 ((uint32_t)0x00340000) /*!< PLL input clock * 6.5 */
-
+
#define RCC_CFGR_OTGFSPRE ((uint32_t)0x00400000) /*!< USB OTG FS prescaler */
-
+
/*!< MCO configuration */
#define RCC_CFGR_MCO ((uint32_t)0x0F000000) /*!< MCO[3:0] bits (Microcontroller Clock Output) */
#define RCC_CFGR_MCO_0 ((uint32_t)0x01000000) /*!< Bit 0 */
@@ -1746,7 +1793,7 @@ typedef struct
#define RCC_CFGR_MCO_PLL3CLK_Div2 ((uint32_t)0x09000000) /*!< PLL3 clock divided by 2 selected as MCO source*/
#define RCC_CFGR_MCO_Ext_HSE ((uint32_t)0x0A000000) /*!< XT1 external 3-25 MHz oscillator clock selected as MCO source */
#define RCC_CFGR_MCO_PLL3CLK ((uint32_t)0x0B000000) /*!< PLL3 clock selected as MCO source */
-#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
#define RCC_CFGR_PLLSRC_HSI_Div2 ((uint32_t)0x00000000) /*!< HSI clock divided by 2 selected as PLL entry clock source */
#define RCC_CFGR_PLLSRC_PREDIV1 ((uint32_t)0x00010000) /*!< PREDIV1 clock selected as PLL entry clock source */
@@ -1853,7 +1900,7 @@ typedef struct
#define RCC_APB2RSTR_IOPDRST ((uint32_t)0x00000020) /*!< I/O port D reset */
#define RCC_APB2RSTR_ADC1RST ((uint32_t)0x00000200) /*!< ADC 1 interface reset */
-#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL)
+#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL)
#define RCC_APB2RSTR_ADC2RST ((uint32_t)0x00000400) /*!< ADC 2 interface reset */
#endif
@@ -1861,7 +1908,7 @@ typedef struct
#define RCC_APB2RSTR_SPI1RST ((uint32_t)0x00001000) /*!< SPI 1 reset */
#define RCC_APB2RSTR_USART1RST ((uint32_t)0x00004000) /*!< USART1 reset */
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
#define RCC_APB2RSTR_TIM15RST ((uint32_t)0x00010000) /*!< TIM15 Timer reset */
#define RCC_APB2RSTR_TIM16RST ((uint32_t)0x00020000) /*!< TIM16 Timer reset */
#define RCC_APB2RSTR_TIM17RST ((uint32_t)0x00040000) /*!< TIM17 Timer reset */
@@ -1878,6 +1925,11 @@ typedef struct
#define RCC_APB2RSTR_ADC3RST ((uint32_t)0x00008000) /*!< ADC3 interface reset */
#endif
+#if defined (STM32F10X_HD_VL)
+ #define RCC_APB2RSTR_IOPFRST ((uint32_t)0x00000080) /*!< I/O port F reset */
+ #define RCC_APB2RSTR_IOPGRST ((uint32_t)0x00000100) /*!< I/O port G reset */
+#endif
+
#ifdef STM32F10X_XL
#define RCC_APB2RSTR_TIM9RST ((uint32_t)0x00080000) /*!< TIM9 Timer reset */
#define RCC_APB2RSTR_TIM10RST ((uint32_t)0x00100000) /*!< TIM10 Timer reset */
@@ -1891,7 +1943,7 @@ typedef struct
#define RCC_APB1RSTR_USART2RST ((uint32_t)0x00020000) /*!< USART 2 reset */
#define RCC_APB1RSTR_I2C1RST ((uint32_t)0x00200000) /*!< I2C 1 reset */
-#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL)
+#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL)
#define RCC_APB1RSTR_CAN1RST ((uint32_t)0x02000000) /*!< CAN1 reset */
#endif
@@ -1919,11 +1971,21 @@ typedef struct
#define RCC_APB1RSTR_DACRST ((uint32_t)0x20000000) /*!< DAC interface reset */
#endif
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
#define RCC_APB1RSTR_TIM6RST ((uint32_t)0x00000010) /*!< Timer 6 reset */
#define RCC_APB1RSTR_TIM7RST ((uint32_t)0x00000020) /*!< Timer 7 reset */
#define RCC_APB1RSTR_DACRST ((uint32_t)0x20000000) /*!< DAC interface reset */
- #define RCC_APB1RSTR_CECRST ((uint32_t)0x40000000) /*!< CEC interface reset */
+ #define RCC_APB1RSTR_CECRST ((uint32_t)0x40000000) /*!< CEC interface reset */
+#endif
+
+#if defined (STM32F10X_HD_VL)
+ #define RCC_APB1RSTR_TIM5RST ((uint32_t)0x00000008) /*!< Timer 5 reset */
+ #define RCC_APB1RSTR_TIM12RST ((uint32_t)0x00000040) /*!< TIM12 Timer reset */
+ #define RCC_APB1RSTR_TIM13RST ((uint32_t)0x00000080) /*!< TIM13 Timer reset */
+ #define RCC_APB1RSTR_TIM14RST ((uint32_t)0x00000100) /*!< TIM14 Timer reset */
+ #define RCC_APB1RSTR_SPI3RST ((uint32_t)0x00008000) /*!< SPI 3 reset */
+ #define RCC_APB1RSTR_UART4RST ((uint32_t)0x00080000) /*!< UART 4 reset */
+ #define RCC_APB1RSTR_UART5RST ((uint32_t)0x00100000) /*!< UART 5 reset */
#endif
#ifdef STM32F10X_CL
@@ -1942,7 +2004,7 @@ typedef struct
#define RCC_AHBENR_FLITFEN ((uint16_t)0x0010) /*!< FLITF clock enable */
#define RCC_AHBENR_CRCEN ((uint16_t)0x0040) /*!< CRC clock enable */
-#if defined (STM32F10X_HD) || defined (STM32F10X_CL)
+#if defined (STM32F10X_HD) || defined (STM32F10X_CL) || defined (STM32F10X_HD_VL) || defined (STM32F10X_XL)
#define RCC_AHBENR_DMA2EN ((uint16_t)0x0002) /*!< DMA2 clock enable */
#endif
@@ -1951,6 +2013,10 @@ typedef struct
#define RCC_AHBENR_SDIOEN ((uint16_t)0x0400) /*!< SDIO clock enable */
#endif
+#if defined (STM32F10X_HD_VL)
+ #define RCC_AHBENR_FSMCEN ((uint16_t)0x0100) /*!< FSMC clock enable */
+#endif
+
#ifdef STM32F10X_CL
#define RCC_AHBENR_OTGFSEN ((uint32_t)0x00001000) /*!< USB OTG FS clock enable */
#define RCC_AHBENR_ETHMACEN ((uint32_t)0x00004000) /*!< ETHERNET MAC clock enable */
@@ -1966,7 +2032,7 @@ typedef struct
#define RCC_APB2ENR_IOPDEN ((uint32_t)0x00000020) /*!< I/O port D clock enable */
#define RCC_APB2ENR_ADC1EN ((uint32_t)0x00000200) /*!< ADC 1 interface clock enable */
-#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL)
+#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL)
#define RCC_APB2ENR_ADC2EN ((uint32_t)0x00000400) /*!< ADC 2 interface clock enable */
#endif
@@ -1974,7 +2040,7 @@ typedef struct
#define RCC_APB2ENR_SPI1EN ((uint32_t)0x00001000) /*!< SPI 1 clock enable */
#define RCC_APB2ENR_USART1EN ((uint32_t)0x00004000) /*!< USART1 clock enable */
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
#define RCC_APB2ENR_TIM15EN ((uint32_t)0x00010000) /*!< TIM15 Timer clock enable */
#define RCC_APB2ENR_TIM16EN ((uint32_t)0x00020000) /*!< TIM16 Timer clock enable */
#define RCC_APB2ENR_TIM17EN ((uint32_t)0x00040000) /*!< TIM17 Timer clock enable */
@@ -1991,6 +2057,11 @@ typedef struct
#define RCC_APB2ENR_ADC3EN ((uint32_t)0x00008000) /*!< DMA1 clock enable */
#endif
+#if defined (STM32F10X_HD_VL)
+ #define RCC_APB2ENR_IOPFEN ((uint32_t)0x00000080) /*!< I/O port F clock enable */
+ #define RCC_APB2ENR_IOPGEN ((uint32_t)0x00000100) /*!< I/O port G clock enable */
+#endif
+
#ifdef STM32F10X_XL
#define RCC_APB2ENR_TIM9EN ((uint32_t)0x00080000) /*!< TIM9 Timer clock enable */
#define RCC_APB2ENR_TIM10EN ((uint32_t)0x00100000) /*!< TIM10 Timer clock enable */
@@ -2004,7 +2075,7 @@ typedef struct
#define RCC_APB1ENR_USART2EN ((uint32_t)0x00020000) /*!< USART 2 clock enable */
#define RCC_APB1ENR_I2C1EN ((uint32_t)0x00200000) /*!< I2C 1 clock enable */
-#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL)
+#if !defined (STM32F10X_LD_VL) && !defined (STM32F10X_MD_VL) && !defined (STM32F10X_HD_VL)
#define RCC_APB1ENR_CAN1EN ((uint32_t)0x02000000) /*!< CAN1 clock enable */
#endif
@@ -2032,13 +2103,23 @@ typedef struct
#define RCC_APB1ENR_DACEN ((uint32_t)0x20000000) /*!< DAC interface clock enable */
#endif
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
#define RCC_APB1ENR_TIM6EN ((uint32_t)0x00000010) /*!< Timer 6 clock enable */
#define RCC_APB1ENR_TIM7EN ((uint32_t)0x00000020) /*!< Timer 7 clock enable */
#define RCC_APB1ENR_DACEN ((uint32_t)0x20000000) /*!< DAC interface clock enable */
- #define RCC_APB1ENR_CECEN ((uint32_t)0x40000000) /*!< CEC interface clock enable */
+ #define RCC_APB1ENR_CECEN ((uint32_t)0x40000000) /*!< CEC interface clock enable */
#endif
+#ifdef STM32F10X_HD_VL
+ #define RCC_APB1ENR_TIM5EN ((uint32_t)0x00000008) /*!< Timer 5 clock enable */
+ #define RCC_APB1ENR_TIM12EN ((uint32_t)0x00000040) /*!< TIM12 Timer clock enable */
+ #define RCC_APB1ENR_TIM13EN ((uint32_t)0x00000080) /*!< TIM13 Timer clock enable */
+ #define RCC_APB1ENR_TIM14EN ((uint32_t)0x00000100) /*!< TIM14 Timer clock enable */
+ #define RCC_APB1ENR_SPI3EN ((uint32_t)0x00008000) /*!< SPI 3 clock enable */
+ #define RCC_APB1ENR_UART4EN ((uint32_t)0x00080000) /*!< UART 4 clock enable */
+ #define RCC_APB1ENR_UART5EN ((uint32_t)0x00100000) /*!< UART 5 clock enable */
+#endif /* STM32F10X_HD_VL */
+
#ifdef STM32F10X_CL
#define RCC_APB1ENR_CAN2EN ((uint32_t)0x04000000) /*!< CAN2 clock enable */
#endif /* STM32F10X_CL */
@@ -2067,7 +2148,7 @@ typedef struct
#define RCC_BDCR_RTCEN ((uint32_t)0x00008000) /*!< RTC clock enable */
#define RCC_BDCR_BDRST ((uint32_t)0x00010000) /*!< Backup domain software reset */
-/******************* Bit definition for RCC_CSR register ********************/
+/******************* Bit definition for RCC_CSR register ********************/
#define RCC_CSR_LSION ((uint32_t)0x00000001) /*!< Internal Low Speed oscillator enable */
#define RCC_CSR_LSIRDY ((uint32_t)0x00000002) /*!< Internal Low Speed oscillator Ready */
#define RCC_CSR_RMVF ((uint32_t)0x01000000) /*!< Remove reset flag */
@@ -2173,7 +2254,7 @@ typedef struct
#define RCC_CFGR2_I2S3SRC ((uint32_t)0x00040000) /*!< I2S3 clock source */
#endif /* STM32F10X_CL */
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
/******************* Bit definition for RCC_CFGR2 register ******************/
/*!< PREDIV1 configuration */
#define RCC_CFGR2_PREDIV1 ((uint32_t)0x0000000F) /*!< PREDIV1[3:0] bits */
@@ -2199,7 +2280,7 @@ typedef struct
#define RCC_CFGR2_PREDIV1_DIV15 ((uint32_t)0x0000000E) /*!< PREDIV1 input clock divided by 15 */
#define RCC_CFGR2_PREDIV1_DIV16 ((uint32_t)0x0000000F) /*!< PREDIV1 input clock divided by 16 */
#endif
-
+
/******************************************************************************/
/* */
/* General Purpose and Alternate Function I/O */
@@ -2609,7 +2690,7 @@ typedef struct
#define AFIO_EXTICR1_EXTI1_PF ((uint16_t)0x0050) /*!< PF[1] pin */
#define AFIO_EXTICR1_EXTI1_PG ((uint16_t)0x0060) /*!< PG[1] pin */
-/*!< EXTI2 configuration */
+/*!< EXTI2 configuration */
#define AFIO_EXTICR1_EXTI2_PA ((uint16_t)0x0000) /*!< PA[2] pin */
#define AFIO_EXTICR1_EXTI2_PB ((uint16_t)0x0100) /*!< PB[2] pin */
#define AFIO_EXTICR1_EXTI2_PC ((uint16_t)0x0200) /*!< PC[2] pin */
@@ -2651,7 +2732,7 @@ typedef struct
#define AFIO_EXTICR2_EXTI5_PF ((uint16_t)0x0050) /*!< PF[5] pin */
#define AFIO_EXTICR2_EXTI5_PG ((uint16_t)0x0060) /*!< PG[5] pin */
-/*!< EXTI6 configuration */
+/*!< EXTI6 configuration */
#define AFIO_EXTICR2_EXTI6_PA ((uint16_t)0x0000) /*!< PA[6] pin */
#define AFIO_EXTICR2_EXTI6_PB ((uint16_t)0x0100) /*!< PB[6] pin */
#define AFIO_EXTICR2_EXTI6_PC ((uint16_t)0x0200) /*!< PC[6] pin */
@@ -2693,7 +2774,7 @@ typedef struct
#define AFIO_EXTICR3_EXTI9_PF ((uint16_t)0x0050) /*!< PF[9] pin */
#define AFIO_EXTICR3_EXTI9_PG ((uint16_t)0x0060) /*!< PG[9] pin */
-/*!< EXTI10 configuration */
+/*!< EXTI10 configuration */
#define AFIO_EXTICR3_EXTI10_PA ((uint16_t)0x0000) /*!< PA[10] pin */
#define AFIO_EXTICR3_EXTI10_PB ((uint16_t)0x0100) /*!< PB[10] pin */
#define AFIO_EXTICR3_EXTI10_PC ((uint16_t)0x0200) /*!< PC[10] pin */
@@ -2735,7 +2816,7 @@ typedef struct
#define AFIO_EXTICR4_EXTI13_PF ((uint16_t)0x0050) /*!< PF[13] pin */
#define AFIO_EXTICR4_EXTI13_PG ((uint16_t)0x0060) /*!< PG[13] pin */
-/*!< EXTI14 configuration */
+/*!< EXTI14 configuration */
#define AFIO_EXTICR4_EXTI14_PA ((uint16_t)0x0000) /*!< PA[14] pin */
#define AFIO_EXTICR4_EXTI14_PB ((uint16_t)0x0100) /*!< PB[14] pin */
#define AFIO_EXTICR4_EXTI14_PC ((uint16_t)0x0200) /*!< PC[14] pin */
@@ -2753,7 +2834,7 @@ typedef struct
#define AFIO_EXTICR4_EXTI15_PF ((uint16_t)0x5000) /*!< PF[15] pin */
#define AFIO_EXTICR4_EXTI15_PG ((uint16_t)0x6000) /*!< PG[15] pin */
-#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL)
+#if defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || defined (STM32F10X_HD_VL)
/****************** Bit definition for AFIO_MAPR2 register ******************/
#define AFIO_MAPR2_TIM15_REMAP ((uint32_t)0x00000001) /*!< TIM15 remapping */
#define AFIO_MAPR2_TIM16_REMAP ((uint32_t)0x00000002) /*!< TIM16 remapping */
@@ -2762,7 +2843,16 @@ typedef struct
#define AFIO_MAPR2_TIM1_DMA_REMAP ((uint32_t)0x00000010) /*!< TIM1_DMA remapping */
#endif
-#ifdef STM32F10X_XL
+#ifdef STM32F10X_HD_VL
+#define AFIO_MAPR2_TIM13_REMAP ((uint32_t)0x00000100) /*!< TIM13 remapping */
+#define AFIO_MAPR2_TIM14_REMAP ((uint32_t)0x00000200) /*!< TIM14 remapping */
+#define AFIO_MAPR2_FSMC_NADV_REMAP ((uint32_t)0x00000400) /*!< FSMC NADV remapping */
+#define AFIO_MAPR2_TIM67_DAC_DMA_REMAP ((uint32_t)0x00000800) /*!< TIM6/TIM7 and DAC DMA remapping */
+#define AFIO_MAPR2_TIM12_REMAP ((uint32_t)0x00001000) /*!< TIM12 remapping */
+#define AFIO_MAPR2_MISC_REMAP ((uint32_t)0x00002000) /*!< Miscellaneous remapping */
+#endif
+
+#ifdef STM32F10X_XL
/****************** Bit definition for AFIO_MAPR2 register ******************/
#define AFIO_MAPR2_TIM9_REMAP ((uint32_t)0x00000020) /*!< TIM9 remapping */
#define AFIO_MAPR2_TIM10_REMAP ((uint32_t)0x00000040) /*!< TIM10 remapping */
@@ -3630,7 +3720,7 @@ typedef struct
#define ADC_CR1_JAWDEN ((uint32_t)0x00400000) /*!<Analog watchdog enable on injected channels */
#define ADC_CR1_AWDEN ((uint32_t)0x00800000) /*!<Analog watchdog enable on regular channels */
-
+
/******************* Bit definition for ADC_CR2 register ********************/
#define ADC_CR2_ADON ((uint32_t)0x00000001) /*!<A/D Converter ON / OFF */
#define ADC_CR2_CONT ((uint32_t)0x00000002) /*!<Continuous Conversion */
@@ -3888,7 +3978,7 @@ typedef struct
#define ADC_SQR3_SQ6_4 ((uint32_t)0x20000000) /*!<Bit 4 */
/******************* Bit definition for ADC_JSQR register *******************/
-#define ADC_JSQR_JSQ1 ((uint32_t)0x0000001F) /*!<JSQ1[4:0] bits (1st conversion in injected sequence) */
+#define ADC_JSQR_JSQ1 ((uint32_t)0x0000001F) /*!<JSQ1[4:0] bits (1st conversion in injected sequence) */
#define ADC_JSQR_JSQ1_0 ((uint32_t)0x00000001) /*!<Bit 0 */
#define ADC_JSQR_JSQ1_1 ((uint32_t)0x00000002) /*!<Bit 1 */
#define ADC_JSQR_JSQ1_2 ((uint32_t)0x00000004) /*!<Bit 2 */
@@ -4300,6 +4390,7 @@ typedef struct
#define TIM_CCER_CC3NP ((uint16_t)0x0800) /*!<Capture/Compare 3 Complementary output Polarity */
#define TIM_CCER_CC4E ((uint16_t)0x1000) /*!<Capture/Compare 4 output enable */
#define TIM_CCER_CC4P ((uint16_t)0x2000) /*!<Capture/Compare 4 output Polarity */
+#define TIM_CCER_CC4NP ((uint16_t)0x8000) /*!<Capture/Compare 4 Complementary output Polarity */
/******************* Bit definition for TIM_CNT register ********************/
#define TIM_CNT_CNT ((uint16_t)0xFFFF) /*!<Counter Value */
@@ -4493,6 +4584,7 @@ typedef struct
#define FSMC_BCR1_WREN ((uint32_t)0x00001000) /*!<Write enable bit */
#define FSMC_BCR1_WAITEN ((uint32_t)0x00002000) /*!<Wait enable bit */
#define FSMC_BCR1_EXTMOD ((uint32_t)0x00004000) /*!<Extended mode enable */
+#define FSMC_BCR1_ASYNCWAIT ((uint32_t)0x00008000) /*!<Asynchronous wait */
#define FSMC_BCR1_CBURSTRW ((uint32_t)0x00080000) /*!<Write burst enable */
/****************** Bit definition for FSMC_BCR2 register *******************/
@@ -4515,6 +4607,7 @@ typedef struct
#define FSMC_BCR2_WREN ((uint32_t)0x00001000) /*!<Write enable bit */
#define FSMC_BCR2_WAITEN ((uint32_t)0x00002000) /*!<Wait enable bit */
#define FSMC_BCR2_EXTMOD ((uint32_t)0x00004000) /*!<Extended mode enable */
+#define FSMC_BCR2_ASYNCWAIT ((uint32_t)0x00008000) /*!<Asynchronous wait */
#define FSMC_BCR2_CBURSTRW ((uint32_t)0x00080000) /*!<Write burst enable */
/****************** Bit definition for FSMC_BCR3 register *******************/
@@ -4537,6 +4630,7 @@ typedef struct
#define FSMC_BCR3_WREN ((uint32_t)0x00001000) /*!<Write enable bit */
#define FSMC_BCR3_WAITEN ((uint32_t)0x00002000) /*!<Wait enable bit */
#define FSMC_BCR3_EXTMOD ((uint32_t)0x00004000) /*!<Extended mode enable */
+#define FSMC_BCR3_ASYNCWAIT ((uint32_t)0x00008000) /*!<Asynchronous wait */
#define FSMC_BCR3_CBURSTRW ((uint32_t)0x00080000) /*!<Write burst enable */
/****************** Bit definition for FSMC_BCR4 register *******************/
@@ -4559,6 +4653,7 @@ typedef struct
#define FSMC_BCR4_WREN ((uint32_t)0x00001000) /*!<Write enable bit */
#define FSMC_BCR4_WAITEN ((uint32_t)0x00002000) /*!<Wait enable bit */
#define FSMC_BCR4_EXTMOD ((uint32_t)0x00004000) /*!<Extended mode enable */
+#define FSMC_BCR4_ASYNCWAIT ((uint32_t)0x00008000) /*!<Asynchronous wait */
#define FSMC_BCR4_CBURSTRW ((uint32_t)0x00080000) /*!<Write burst enable */
/****************** Bit definition for FSMC_BTR1 register ******************/
@@ -5674,7 +5769,7 @@ typedef struct
#define USB_DADDR_EF ((uint8_t)0x80) /*!<Enable Function */
-/****************** Bit definition for USB_BTABLE register ******************/
+/****************** Bit definition for USB_BTABLE register ******************/
#define USB_BTABLE_BTABLE ((uint16_t)0xFFF8) /*!<Buffer Table */
/*!<Buffer descriptor table */
@@ -6258,7 +6353,7 @@ typedef struct
#define CAN_TI2R_EXID ((uint32_t)0x001FFFF8) /*!<Extended identifier */
#define CAN_TI2R_STID ((uint32_t)0xFFE00000) /*!<Standard Identifier or Extended Identifier */
-/******************* Bit definition for CAN_TDT2R register ******************/
+/******************* Bit definition for CAN_TDT2R register ******************/
#define CAN_TDT2R_DLC ((uint32_t)0x0000000F) /*!<Data Length Code */
#define CAN_TDT2R_TGT ((uint32_t)0x00000100) /*!<Transmit Global Time */
#define CAN_TDT2R_TIME ((uint32_t)0xFFFF0000) /*!<Message Time Stamp */
@@ -7771,10 +7866,10 @@ typedef struct
#define ETH_MACCR_IFG_88Bit ((uint32_t)0x00020000) /* Minimum IFG between frames during transmission is 88Bit */
#define ETH_MACCR_IFG_80Bit ((uint32_t)0x00040000) /* Minimum IFG between frames during transmission is 80Bit */
#define ETH_MACCR_IFG_72Bit ((uint32_t)0x00060000) /* Minimum IFG between frames during transmission is 72Bit */
- #define ETH_MACCR_IFG_64Bit ((uint32_t)0x00080000) /* Minimum IFG between frames during transmission is 64Bit */
+ #define ETH_MACCR_IFG_64Bit ((uint32_t)0x00080000) /* Minimum IFG between frames during transmission is 64Bit */
#define ETH_MACCR_IFG_56Bit ((uint32_t)0x000A0000) /* Minimum IFG between frames during transmission is 56Bit */
#define ETH_MACCR_IFG_48Bit ((uint32_t)0x000C0000) /* Minimum IFG between frames during transmission is 48Bit */
- #define ETH_MACCR_IFG_40Bit ((uint32_t)0x000E0000) /* Minimum IFG between frames during transmission is 40Bit */
+ #define ETH_MACCR_IFG_40Bit ((uint32_t)0x000E0000) /* Minimum IFG between frames during transmission is 40Bit */
#define ETH_MACCR_CSD ((uint32_t)0x00010000) /* Carrier sense disable (during transmission) */
#define ETH_MACCR_FES ((uint32_t)0x00004000) /* Fast ethernet speed */
#define ETH_MACCR_ROD ((uint32_t)0x00002000) /* Receive own disable */
@@ -7788,24 +7883,24 @@ typedef struct
#define ETH_MACCR_BL_10 ((uint32_t)0x00000000) /* k = min (n, 10) */
#define ETH_MACCR_BL_8 ((uint32_t)0x00000020) /* k = min (n, 8) */
#define ETH_MACCR_BL_4 ((uint32_t)0x00000040) /* k = min (n, 4) */
- #define ETH_MACCR_BL_1 ((uint32_t)0x00000060) /* k = min (n, 1) */
+ #define ETH_MACCR_BL_1 ((uint32_t)0x00000060) /* k = min (n, 1) */
#define ETH_MACCR_DC ((uint32_t)0x00000010) /* Defferal check */
#define ETH_MACCR_TE ((uint32_t)0x00000008) /* Transmitter enable */
#define ETH_MACCR_RE ((uint32_t)0x00000004) /* Receiver enable */
/* Bit definition for Ethernet MAC Frame Filter Register */
-#define ETH_MACFFR_RA ((uint32_t)0x80000000) /* Receive all */
-#define ETH_MACFFR_HPF ((uint32_t)0x00000400) /* Hash or perfect filter */
-#define ETH_MACFFR_SAF ((uint32_t)0x00000200) /* Source address filter enable */
-#define ETH_MACFFR_SAIF ((uint32_t)0x00000100) /* SA inverse filtering */
+#define ETH_MACFFR_RA ((uint32_t)0x80000000) /* Receive all */
+#define ETH_MACFFR_HPF ((uint32_t)0x00000400) /* Hash or perfect filter */
+#define ETH_MACFFR_SAF ((uint32_t)0x00000200) /* Source address filter enable */
+#define ETH_MACFFR_SAIF ((uint32_t)0x00000100) /* SA inverse filtering */
#define ETH_MACFFR_PCF ((uint32_t)0x000000C0) /* Pass control frames: 3 cases */
#define ETH_MACFFR_PCF_BlockAll ((uint32_t)0x00000040) /* MAC filters all control frames from reaching the application */
#define ETH_MACFFR_PCF_ForwardAll ((uint32_t)0x00000080) /* MAC forwards all control frames to application even if they fail the Address Filter */
- #define ETH_MACFFR_PCF_ForwardPassedAddrFilter ((uint32_t)0x000000C0) /* MAC forwards control frames that pass the Address Filter. */
-#define ETH_MACFFR_BFD ((uint32_t)0x00000020) /* Broadcast frame disable */
-#define ETH_MACFFR_PAM ((uint32_t)0x00000010) /* Pass all mutlicast */
-#define ETH_MACFFR_DAIF ((uint32_t)0x00000008) /* DA Inverse filtering */
-#define ETH_MACFFR_HM ((uint32_t)0x00000004) /* Hash multicast */
+ #define ETH_MACFFR_PCF_ForwardPassedAddrFilter ((uint32_t)0x000000C0) /* MAC forwards control frames that pass the Address Filter. */
+#define ETH_MACFFR_BFD ((uint32_t)0x00000020) /* Broadcast frame disable */
+#define ETH_MACFFR_PAM ((uint32_t)0x00000010) /* Pass all mutlicast */
+#define ETH_MACFFR_DAIF ((uint32_t)0x00000008) /* DA Inverse filtering */
+#define ETH_MACFFR_HM ((uint32_t)0x00000004) /* Hash multicast */
#define ETH_MACFFR_HU ((uint32_t)0x00000002) /* Hash unicast */
#define ETH_MACFFR_PM ((uint32_t)0x00000001) /* Promiscuous mode */
@@ -7816,15 +7911,15 @@ typedef struct
#define ETH_MACHTLR_HTL ((uint32_t)0xFFFFFFFF) /* Hash table low */
/* Bit definition for Ethernet MAC MII Address Register */
-#define ETH_MACMIIAR_PA ((uint32_t)0x0000F800) /* Physical layer address */
-#define ETH_MACMIIAR_MR ((uint32_t)0x000007C0) /* MII register in the selected PHY */
-#define ETH_MACMIIAR_CR ((uint32_t)0x0000001C) /* CR clock range: 6 cases */
+#define ETH_MACMIIAR_PA ((uint32_t)0x0000F800) /* Physical layer address */
+#define ETH_MACMIIAR_MR ((uint32_t)0x000007C0) /* MII register in the selected PHY */
+#define ETH_MACMIIAR_CR ((uint32_t)0x0000001C) /* CR clock range: 6 cases */
#define ETH_MACMIIAR_CR_Div42 ((uint32_t)0x00000000) /* HCLK:60-72 MHz; MDC clock= HCLK/42 */
#define ETH_MACMIIAR_CR_Div16 ((uint32_t)0x00000008) /* HCLK:20-35 MHz; MDC clock= HCLK/16 */
#define ETH_MACMIIAR_CR_Div26 ((uint32_t)0x0000000C) /* HCLK:35-60 MHz; MDC clock= HCLK/26 */
-#define ETH_MACMIIAR_MW ((uint32_t)0x00000002) /* MII write */
-#define ETH_MACMIIAR_MB ((uint32_t)0x00000001) /* MII busy */
-
+#define ETH_MACMIIAR_MW ((uint32_t)0x00000002) /* MII write */
+#define ETH_MACMIIAR_MB ((uint32_t)0x00000001) /* MII busy */
+
/* Bit definition for Ethernet MAC MII Data Register */
#define ETH_MACMIIDR_MD ((uint32_t)0x0000FFFF) /* MII data: read/write data from/to PHY */
@@ -7835,7 +7930,7 @@ typedef struct
#define ETH_MACFCR_PLT_Minus4 ((uint32_t)0x00000000) /* Pause time minus 4 slot times */
#define ETH_MACFCR_PLT_Minus28 ((uint32_t)0x00000010) /* Pause time minus 28 slot times */
#define ETH_MACFCR_PLT_Minus144 ((uint32_t)0x00000020) /* Pause time minus 144 slot times */
- #define ETH_MACFCR_PLT_Minus256 ((uint32_t)0x00000030) /* Pause time minus 256 slot times */
+ #define ETH_MACFCR_PLT_Minus256 ((uint32_t)0x00000030) /* Pause time minus 256 slot times */
#define ETH_MACFCR_UPFD ((uint32_t)0x00000008) /* Unicast pause frame detect */
#define ETH_MACFCR_RFCE ((uint32_t)0x00000004) /* Receive flow control enable */
#define ETH_MACFCR_TFCE ((uint32_t)0x00000002) /* Transmit flow control enable */
@@ -7845,7 +7940,7 @@ typedef struct
#define ETH_MACVLANTR_VLANTC ((uint32_t)0x00010000) /* 12-bit VLAN tag comparison */
#define ETH_MACVLANTR_VLANTI ((uint32_t)0x0000FFFF) /* VLAN tag identifier (for receive frames) */
-/* Bit definition for Ethernet MAC Remote Wake-UpFrame Filter Register */
+/* Bit definition for Ethernet MAC Remote Wake-UpFrame Filter Register */
#define ETH_MACRWUFFR_D ((uint32_t)0xFFFFFFFF) /* Wake-up frame filter register data */
/* Eight sequential Writes to this address (offset 0x28) will write all Wake-UpFrame Filter Registers.
Eight sequential Reads from this address (offset 0x28) will read all Wake-UpFrame Filter Registers. */
@@ -7853,13 +7948,13 @@ typedef struct
Wake-UpFrame Filter Reg1 : Filter 1 Byte Mask
Wake-UpFrame Filter Reg2 : Filter 2 Byte Mask
Wake-UpFrame Filter Reg3 : Filter 3 Byte Mask
- Wake-UpFrame Filter Reg4 : RSVD - Filter3 Command - RSVD - Filter2 Command -
+ Wake-UpFrame Filter Reg4 : RSVD - Filter3 Command - RSVD - Filter2 Command -
RSVD - Filter1 Command - RSVD - Filter0 Command
Wake-UpFrame Filter Re5 : Filter3 Offset - Filter2 Offset - Filter1 Offset - Filter0 Offset
Wake-UpFrame Filter Re6 : Filter1 CRC16 - Filter0 CRC16
Wake-UpFrame Filter Re7 : Filter3 CRC16 - Filter2 CRC16 */
-/* Bit definition for Ethernet MAC PMT Control and Status Register */
+/* Bit definition for Ethernet MAC PMT Control and Status Register */
#define ETH_MACPMTCSR_WFFRPR ((uint32_t)0x80000000) /* Wake-Up Frame Filter Register Pointer Reset */
#define ETH_MACPMTCSR_GU ((uint32_t)0x00000200) /* Global Unicast */
#define ETH_MACPMTCSR_WFR ((uint32_t)0x00000040) /* Wake-Up Frame Received */
@@ -7894,7 +7989,7 @@ typedef struct
#define ETH_MACA1HR_MBC_LBits31_24 ((uint32_t)0x08000000) /* Mask MAC Address low reg bits [31:24] */
#define ETH_MACA1HR_MBC_LBits23_16 ((uint32_t)0x04000000) /* Mask MAC Address low reg bits [23:16] */
#define ETH_MACA1HR_MBC_LBits15_8 ((uint32_t)0x02000000) /* Mask MAC Address low reg bits [15:8] */
- #define ETH_MACA1HR_MBC_LBits7_0 ((uint32_t)0x01000000) /* Mask MAC Address low reg bits [7:0] */
+ #define ETH_MACA1HR_MBC_LBits7_0 ((uint32_t)0x01000000) /* Mask MAC Address low reg bits [7:0] */
#define ETH_MACA1HR_MACA1H ((uint32_t)0x0000FFFF) /* MAC address1 high */
/* Bit definition for Ethernet MAC Address1 Low Register */
@@ -8030,26 +8125,26 @@ typedef struct
#define ETH_DMABMR_RDP_4Beat ((uint32_t)0x00080000) /* maximum number of beats to be transferred in one RxDMA transaction is 4 */
#define ETH_DMABMR_RDP_8Beat ((uint32_t)0x00100000) /* maximum number of beats to be transferred in one RxDMA transaction is 8 */
#define ETH_DMABMR_RDP_16Beat ((uint32_t)0x00200000) /* maximum number of beats to be transferred in one RxDMA transaction is 16 */
- #define ETH_DMABMR_RDP_32Beat ((uint32_t)0x00400000) /* maximum number of beats to be transferred in one RxDMA transaction is 32 */
+ #define ETH_DMABMR_RDP_32Beat ((uint32_t)0x00400000) /* maximum number of beats to be transferred in one RxDMA transaction is 32 */
#define ETH_DMABMR_RDP_4xPBL_4Beat ((uint32_t)0x01020000) /* maximum number of beats to be transferred in one RxDMA transaction is 4 */
#define ETH_DMABMR_RDP_4xPBL_8Beat ((uint32_t)0x01040000) /* maximum number of beats to be transferred in one RxDMA transaction is 8 */
#define ETH_DMABMR_RDP_4xPBL_16Beat ((uint32_t)0x01080000) /* maximum number of beats to be transferred in one RxDMA transaction is 16 */
#define ETH_DMABMR_RDP_4xPBL_32Beat ((uint32_t)0x01100000) /* maximum number of beats to be transferred in one RxDMA transaction is 32 */
#define ETH_DMABMR_RDP_4xPBL_64Beat ((uint32_t)0x01200000) /* maximum number of beats to be transferred in one RxDMA transaction is 64 */
- #define ETH_DMABMR_RDP_4xPBL_128Beat ((uint32_t)0x01400000) /* maximum number of beats to be transferred in one RxDMA transaction is 128 */
+ #define ETH_DMABMR_RDP_4xPBL_128Beat ((uint32_t)0x01400000) /* maximum number of beats to be transferred in one RxDMA transaction is 128 */
#define ETH_DMABMR_FB ((uint32_t)0x00010000) /* Fixed Burst */
#define ETH_DMABMR_RTPR ((uint32_t)0x0000C000) /* Rx Tx priority ratio */
#define ETH_DMABMR_RTPR_1_1 ((uint32_t)0x00000000) /* Rx Tx priority ratio */
#define ETH_DMABMR_RTPR_2_1 ((uint32_t)0x00004000) /* Rx Tx priority ratio */
#define ETH_DMABMR_RTPR_3_1 ((uint32_t)0x00008000) /* Rx Tx priority ratio */
- #define ETH_DMABMR_RTPR_4_1 ((uint32_t)0x0000C000) /* Rx Tx priority ratio */
+ #define ETH_DMABMR_RTPR_4_1 ((uint32_t)0x0000C000) /* Rx Tx priority ratio */
#define ETH_DMABMR_PBL ((uint32_t)0x00003F00) /* Programmable burst length */
#define ETH_DMABMR_PBL_1Beat ((uint32_t)0x00000100) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 1 */
#define ETH_DMABMR_PBL_2Beat ((uint32_t)0x00000200) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 2 */
#define ETH_DMABMR_PBL_4Beat ((uint32_t)0x00000400) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */
#define ETH_DMABMR_PBL_8Beat ((uint32_t)0x00000800) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */
#define ETH_DMABMR_PBL_16Beat ((uint32_t)0x00001000) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */
- #define ETH_DMABMR_PBL_32Beat ((uint32_t)0x00002000) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */
+ #define ETH_DMABMR_PBL_32Beat ((uint32_t)0x00002000) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 32 */
#define ETH_DMABMR_PBL_4xPBL_4Beat ((uint32_t)0x01000100) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 4 */
#define ETH_DMABMR_PBL_4xPBL_8Beat ((uint32_t)0x01000200) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 8 */
#define ETH_DMABMR_PBL_4xPBL_16Beat ((uint32_t)0x01000400) /* maximum number of beats to be transferred in one TxDMA (or both) transaction is 16 */
@@ -8179,7 +8274,7 @@ typedef struct
/**
* @}
- */
+ */
#ifdef USE_STDPERIPH_DRIVER
#include "stm32f10x_conf.h"
diff --git a/os/hal/platforms/STM32/uart_lld.c b/os/hal/platforms/STM32/uart_lld.c
index 9769aa090..e2f306302 100644
--- a/os/hal/platforms/STM32/uart_lld.c
+++ b/os/hal/platforms/STM32/uart_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -90,13 +91,13 @@ static void set_rx_idle_loop(UARTDriver *uartp) {
/* RX DMA channel preparation, if the char callback is defined then the
TCIE interrupt is enabled too.*/
- if (uartp->ud_config->uc_rxchar == NULL)
+ if (uartp->config->rxchar_cb == NULL)
ccr = DMA_CCR1_CIRC | DMA_CCR1_TEIE;
else
ccr = DMA_CCR1_CIRC | DMA_CCR1_TEIE | DMA_CCR1_TCIE;
- dmaSetupChannel(uartp->ud_dmap, uartp->ud_dmarx, 1,
- &uartp->ud_rxbuf, uartp->ud_dmaccr | ccr);
- dmaEnableChannel(uartp->ud_dmap, uartp->ud_dmarx);
+ dmaSetupChannel(uartp->dmap, uartp->dmarx, 1,
+ &uartp->rxbuf, uartp->dmaccr | ccr);
+ dmaEnableChannel(uartp->dmap, uartp->dmarx);
}
/**
@@ -108,15 +109,15 @@ static void set_rx_idle_loop(UARTDriver *uartp) {
static void usart_stop(UARTDriver *uartp) {
/* Stops RX and TX DMA channels.*/
- dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx);
- dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmatx);
- dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx);
- dmaClearChannel(uartp->ud_dmap, uartp->ud_dmatx);
+ dmaDisableChannel(uartp->dmap, uartp->dmarx);
+ dmaDisableChannel(uartp->dmap, uartp->dmatx);
+ dmaClearChannel(uartp->dmap, uartp->dmarx);
+ dmaClearChannel(uartp->dmap, uartp->dmatx);
/* Stops USART operations.*/
- uartp->ud_usart->CR1 = 0;
- uartp->ud_usart->CR2 = 0;
- uartp->ud_usart->CR3 = 0;
+ uartp->usart->CR1 = 0;
+ uartp->usart->CR2 = 0;
+ uartp->usart->CR3 = 0;
}
/**
@@ -127,16 +128,16 @@ static void usart_stop(UARTDriver *uartp) {
*/
static void usart_start(UARTDriver *uartp) {
uint16_t cr1;
- USART_TypeDef *u = uartp->ud_usart;
+ USART_TypeDef *u = uartp->usart;
/* Defensive programming, starting from a clean state.*/
usart_stop(uartp);
/* Baud rate setting.*/
- if (uartp->ud_usart == USART1)
- u->BRR = STM32_PCLK2 / uartp->ud_config->uc_speed;
+ if (uartp->usart == USART1)
+ u->BRR = STM32_PCLK2 / uartp->config->speed;
else
- u->BRR = STM32_PCLK1 / uartp->ud_config->uc_speed;
+ u->BRR = STM32_PCLK1 / uartp->config->speed;
/* Resetting eventual pending status flags.*/
(void)u->SR; /* SR reset step 1.*/
@@ -145,14 +146,14 @@ static void usart_start(UARTDriver *uartp) {
/* Note that some bits are enforced because required for correct driver
operations.*/
- if (uartp->ud_config->uc_txend2 == NULL)
+ if (uartp->config->txend2_cb == NULL)
cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE;
else
cr1 = USART_CR1_UE | USART_CR1_PEIE | USART_CR1_TE | USART_CR1_RE |
USART_CR1_TCIE;
- u->CR1 = uartp->ud_config->uc_cr1 | cr1;
- u->CR2 = uartp->ud_config->uc_cr2 | USART_CR2_LBDIE;
- u->CR3 = uartp->ud_config->uc_cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
+ u->CR1 = uartp->config->cr1 | cr1;
+ u->CR2 = uartp->config->cr2 | USART_CR2_LBDIE;
+ u->CR3 = uartp->config->cr3 | USART_CR3_DMAT | USART_CR3_DMAR |
USART_CR3_EIE;
/* Starting the receiver idle loop.*/
@@ -163,17 +164,38 @@ static void usart_start(UARTDriver *uartp) {
* @brief RX DMA common service routine.
*
* @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
*/
-static void serve_rx_end_irq(UARTDriver *uartp) {
+static void uart_lld_serve_rx_end_irq(UARTDriver *uartp, uint32_t flags) {
- uartp->ud_rxstate = UART_RX_COMPLETE;
- if (uartp->ud_config->uc_rxend != NULL)
- uartp->ud_config->uc_rxend(uartp);
- /* If the callback didn't explicitly change state then the receiver
- automatically returns to the idle state.*/
- if (uartp->ud_rxstate == UART_RX_COMPLETE) {
- uartp->ud_rxstate = UART_RX_IDLE;
- set_rx_idle_loop(uartp);
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & DMA_ISR_TEIF1) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+
+ if (uartp->rxstate == UART_RX_IDLE) {
+ /* Receiver in idle state, a callback is generated, if enabled, for each
+ received character and then the driver stays in the same state.*/
+ if (uartp->config->rxchar_cb != NULL)
+ uartp->config->rxchar_cb(uartp, uartp->rxbuf);
+ }
+ else {
+ /* Receiver in active state, a callback is generated, if enabled, after
+ a completed transfer.*/
+ dmaDisableChannel(uartp->dmap, uartp->dmarx);
+ uartp->rxstate = UART_RX_COMPLETE;
+ if (uartp->config->rxend_cb != NULL)
+ uartp->config->rxend_cb(uartp);
+ /* If the callback didn't explicitly change state then the receiver
+ automatically returns to the idle state.*/
+ if (uartp->rxstate == UART_RX_COMPLETE) {
+ uartp->rxstate = UART_RX_IDLE;
+ set_rx_idle_loop(uartp);
+ }
}
}
@@ -181,18 +203,30 @@ static void serve_rx_end_irq(UARTDriver *uartp) {
* @brief TX DMA common service routine.
*
* @param[in] uartp pointer to the @p UARTDriver object
+ * @param[in] flags pre-shifted content of the ISR register
*/
-static void serve_tx_end_irq(UARTDriver *uartp) {
+static void uart_lld_serve_tx_end_irq(UARTDriver *uartp, uint32_t flags) {
+
+ /* DMA errors handling.*/
+#if defined(STM32_UART_DMA_ERROR_HOOK)
+ if ((flags & DMA_ISR_TEIF1) != 0) {
+ STM32_UART_DMA_ERROR_HOOK(uartp);
+ }
+#else
+ (void)flags;
+#endif
+ dmaDisableChannel(uartp->dmap, uartp->dmatx);
/* A callback is generated, if enabled, after a completed transfer.*/
- uartp->ud_txstate = UART_TX_COMPLETE;
- if (uartp->ud_config->uc_txend1 != NULL)
- uartp->ud_config->uc_txend1(uartp);
+ uartp->txstate = UART_TX_COMPLETE;
+ if (uartp->config->txend1_cb != NULL)
+ uartp->config->txend1_cb(uartp);
/* If the callback didn't explicitly change state then the transmitter
automatically returns to the idle state.*/
- if (uartp->ud_txstate == UART_TX_COMPLETE)
- uartp->ud_txstate = UART_TX_IDLE;
+ if (uartp->txstate == UART_TX_COMPLETE)
+ uartp->txstate = UART_TX_IDLE;
}
+
/**
* @brief USART common service routine.
*
@@ -200,21 +234,21 @@ static void serve_tx_end_irq(UARTDriver *uartp) {
*/
static void serve_usart_irq(UARTDriver *uartp) {
uint16_t sr;
- USART_TypeDef *u = uartp->ud_usart;
+ USART_TypeDef *u = uartp->usart;
sr = u->SR; /* SR reset step 1.*/
(void)u->DR; /* SR reset step 2.*/
if (sr & (USART_SR_LBD | USART_SR_ORE | USART_SR_NE |
USART_SR_FE | USART_SR_PE)) {
u->SR = ~USART_SR_LBD;
- if (uartp->ud_config->uc_rxerr != NULL)
- uartp->ud_config->uc_rxerr(uartp, translate_errors(sr));
+ if (uartp->config->rxerr_cb != NULL)
+ uartp->config->rxerr_cb(uartp, translate_errors(sr));
}
if (sr & USART_SR_TC) {
u->SR = ~USART_SR_TC;
/* End of transmission, a callback is generated.*/
- if (uartp->ud_config->uc_txend2 != NULL)
- uartp->ud_config->uc_txend2(uartp);
+ if (uartp->config->txend2_cb != NULL)
+ uartp->config->txend2_cb(uartp);
}
}
@@ -224,58 +258,6 @@ static void serve_usart_irq(UARTDriver *uartp) {
#if STM32_UART_USE_USART1 || defined(__DOXYGEN__)
/**
- * @brief USART1 RX DMA interrupt handler (channel 5).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch5_IRQHandler) {
- UARTDriver *uartp;
-
- CH_IRQ_PROLOGUE();
-
- uartp = &UARTD1;
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF5) != 0) {
- STM32_UART_USART1_DMA_ERROR_HOOK();
- }
- if (uartp->ud_rxstate == UART_RX_IDLE) {
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
- /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/
- /* Receiver in idle state, a callback is generated, if enabled, for each
- received character and then the driver stays in the same state.*/
- if (uartp->ud_config->uc_rxchar != NULL)
- uartp->ud_config->uc_rxchar(uartp, uartp->ud_rxbuf);
- }
- else {
- /* Receiver in active state, a callback is generated, if enabled, after
- a completed transfer.*/
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_5);
- serve_rx_end_irq(uartp);
- }
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief USART1 TX DMA interrupt handler (channel 4).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch4_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF4) != 0) {
- STM32_UART_USART1_DMA_ERROR_HOOK();
- }
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_4);
- serve_tx_end_irq(&UARTD1);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
* @brief USART1 IRQ handler.
*
* @isr
@@ -292,58 +274,6 @@ CH_IRQ_HANDLER(USART1_IRQHandler) {
#if STM32_UART_USE_USART2 || defined(__DOXYGEN__)
/**
- * @brief USART2 RX DMA interrupt handler (channel 6).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch6_IRQHandler) {
- UARTDriver *uartp;
-
- CH_IRQ_PROLOGUE();
-
- uartp = &UARTD2;
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF6) != 0) {
- STM32_UART_USART2_DMA_ERROR_HOOK();
- }
- if (uartp->ud_rxstate == UART_RX_IDLE) {
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6);
- /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/
- /* Receiver in idle state, a callback is generated, if enabled, for each
- received character and then the driver stays in the same state.*/
- if (uartp->ud_config->uc_rxchar != NULL)
- uartp->ud_config->uc_rxchar(uartp, uartp->ud_rxbuf);
- }
- else {
- /* Receiver in active state, a callback is generated, if enabled, after
- a completed transfer.*/
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_6);
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_6);
- serve_rx_end_irq(uartp);
- }
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief USART2 TX DMA interrupt handler (channel 7).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch7_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF7) != 0) {
- STM32_UART_USART2_DMA_ERROR_HOOK();
- }
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_7);
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_7);
- serve_tx_end_irq(&UARTD2);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
* @brief USART2 IRQ handler.
*
* @isr
@@ -360,58 +290,6 @@ CH_IRQ_HANDLER(USART2_IRQHandler) {
#if STM32_UART_USE_USART3 || defined(__DOXYGEN__)
/**
- * @brief USART3 RX DMA interrupt handler (channel 3).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch3_IRQHandler) {
- UARTDriver *uartp;
-
- CH_IRQ_PROLOGUE();
-
- uartp = &UARTD3;
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF3) != 0) {
- STM32_UART_USART1_DMA_ERROR_HOOK();
- }
- if (uartp->ud_rxstate == UART_RX_IDLE) {
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
- /* Fast IRQ path, this is why it is not centralized in serve_rx_end_irq().*/
- /* Receiver in idle state, a callback is generated, if enabled, for each
- received character and then the driver stays in the same state.*/
- if (uartp->ud_config->uc_rxchar != NULL)
- uartp->ud_config->uc_rxchar(uartp, uartp->ud_rxbuf);
- }
- else {
- /* Receiver in active state, a callback is generated, if enabled, after
- a completed transfer.*/
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_3);
- serve_rx_end_irq(uartp);
- }
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
- * @brief USART3 TX DMA interrupt handler (channel 2).
- *
- * @isr
- */
-CH_IRQ_HANDLER(DMA1_Ch2_IRQHandler) {
-
- CH_IRQ_PROLOGUE();
-
- if ((STM32_DMA1->ISR & DMA_ISR_TEIF2) != 0) {
- STM32_UART_USART1_DMA_ERROR_HOOK();
- }
- dmaClearChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
- dmaDisableChannel(STM32_DMA1, STM32_DMA_CHANNEL_2);
- serve_tx_end_irq(&UARTD3);
-
- CH_IRQ_EPILOGUE();
-}
-
-/**
* @brief USART3 IRQ handler.
*
* @isr
@@ -438,36 +316,30 @@ CH_IRQ_HANDLER(USART3_IRQHandler) {
void uart_lld_init(void) {
#if STM32_UART_USE_USART1
- RCC->APB2RSTR = RCC_APB2RSTR_USART1RST;
- RCC->APB2RSTR = 0;
uartObjectInit(&UARTD1);
- UARTD1.ud_usart = USART1;
- UARTD1.ud_dmap = STM32_DMA1;
- UARTD1.ud_dmarx = STM32_DMA_CHANNEL_5;
- UARTD1.ud_dmatx = STM32_DMA_CHANNEL_4;
- UARTD1.ud_dmaccr = 0;
+ UARTD1.usart = USART1;
+ UARTD1.dmap = STM32_DMA1;
+ UARTD1.dmarx = STM32_DMA_CHANNEL_5;
+ UARTD1.dmatx = STM32_DMA_CHANNEL_4;
+ UARTD1.dmaccr = 0;
#endif
#if STM32_UART_USE_USART2
- RCC->APB1RSTR = RCC_APB1RSTR_USART2RST;
- RCC->APB1RSTR = 0;
uartObjectInit(&UARTD2);
- UARTD2.ud_usart = USART2;
- UARTD2.ud_dmap = STM32_DMA1;
- UARTD2.ud_dmarx = STM32_DMA_CHANNEL_6;
- UARTD2.ud_dmatx = STM32_DMA_CHANNEL_7;
- UARTD2.ud_dmaccr = 0;
+ UARTD2.usart = USART2;
+ UARTD2.dmap = STM32_DMA1;
+ UARTD2.dmarx = STM32_DMA_CHANNEL_6;
+ UARTD2.dmatx = STM32_DMA_CHANNEL_7;
+ UARTD2.dmaccr = 0;
#endif
#if STM32_UART_USE_USART3
- RCC->APB1RSTR = RCC_APB1RSTR_USART3RST;
- RCC->APB1RSTR = 0;
uartObjectInit(&UARTD3);
- UARTD3.ud_usart = USART3;
- UARTD3.ud_dmap = STM32_DMA1;
- UARTD3.ud_dmarx = STM32_DMA_CHANNEL_3;
- UARTD3.ud_dmatx = STM32_DMA_CHANNEL_2;
- UARTD3.ud_dmaccr = 0;
+ UARTD3.usart = USART3;
+ UARTD3.dmap = STM32_DMA1;
+ UARTD3.dmarx = STM32_DMA_CHANNEL_3;
+ UARTD3.dmatx = STM32_DMA_CHANNEL_2;
+ UARTD3.dmaccr = 0;
#endif
}
@@ -480,10 +352,14 @@ void uart_lld_init(void) {
*/
void uart_lld_start(UARTDriver *uartp) {
- if (uartp->ud_state == UART_STOP) {
+ if (uartp->state == UART_STOP) {
#if STM32_UART_USE_USART1
if (&UARTD1 == uartp) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_4,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, (void *)uartp);
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_5,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, (void *)uartp);
NVICEnableVector(USART1_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART1_IRQ_PRIORITY));
NVICEnableVector(DMA1_Channel4_IRQn,
@@ -496,7 +372,11 @@ void uart_lld_start(UARTDriver *uartp) {
#if STM32_UART_USE_USART2
if (&UARTD2 == uartp) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_6,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, (void *)uartp);
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_7,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, (void *)uartp);
NVICEnableVector(USART2_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART2_IRQ_PRIORITY));
NVICEnableVector(DMA1_Channel6_IRQn,
@@ -509,7 +389,11 @@ void uart_lld_start(UARTDriver *uartp) {
#if STM32_UART_USE_USART3
if (&UARTD3 == uartp) {
- dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
+ /* Note, the DMA must be enabled before the IRQs.*/
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_2,
+ (stm32_dmaisr_t)uart_lld_serve_tx_end_irq, (void *)uartp);
+ dmaAllocate(STM32_DMA1_ID, STM32_DMA_CHANNEL_3,
+ (stm32_dmaisr_t)uart_lld_serve_rx_end_irq, (void *)uartp);
NVICEnableVector(USART3_IRQn,
CORTEX_PRIORITY_MASK(STM32_UART_USART3_IRQ_PRIORITY));
NVICEnableVector(DMA1_Channel2_IRQn,
@@ -522,18 +406,18 @@ void uart_lld_start(UARTDriver *uartp) {
/* Static DMA setup, the transfer size depends on the USART settings,
it is 16 bits if M=1 and PCE=0 else it is 8 bits.*/
- uartp->ud_dmaccr = STM32_UART_USART1_DMA_PRIORITY << 12;
- if ((uartp->ud_config->uc_cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M)
- uartp->ud_dmaccr |= DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0;
- dmaChannelSetPeripheral(&uartp->ud_dmap->channels[uartp->ud_dmarx],
- &uartp->ud_usart->DR);
- dmaChannelSetPeripheral(&uartp->ud_dmap->channels[uartp->ud_dmatx],
- &uartp->ud_usart->DR);
- uartp->ud_rxbuf = 0;
+ uartp->dmaccr = STM32_UART_USART1_DMA_PRIORITY << 12;
+ if ((uartp->config->cr1 & (USART_CR1_M | USART_CR1_PCE)) == USART_CR1_M)
+ uartp->dmaccr |= DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0;
+ dmaChannelSetPeripheral(&uartp->dmap->channels[uartp->dmarx],
+ &uartp->usart->DR);
+ dmaChannelSetPeripheral(&uartp->dmap->channels[uartp->dmatx],
+ &uartp->usart->DR);
+ uartp->rxbuf = 0;
}
- uartp->ud_rxstate = UART_RX_IDLE;
- uartp->ud_txstate = UART_TX_IDLE;
+ uartp->rxstate = UART_RX_IDLE;
+ uartp->txstate = UART_TX_IDLE;
usart_start(uartp);
}
@@ -546,7 +430,7 @@ void uart_lld_start(UARTDriver *uartp) {
*/
void uart_lld_stop(UARTDriver *uartp) {
- if (uartp->ud_state == UART_READY) {
+ if (uartp->state == UART_READY) {
usart_stop(uartp);
#if STM32_UART_USE_USART1
@@ -554,7 +438,8 @@ void uart_lld_stop(UARTDriver *uartp) {
NVICDisableVector(USART1_IRQn);
NVICDisableVector(DMA1_Channel4_IRQn);
NVICDisableVector(DMA1_Channel5_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_4);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_5);
RCC->APB2ENR &= ~RCC_APB2ENR_USART1EN;
return;
}
@@ -565,7 +450,8 @@ void uart_lld_stop(UARTDriver *uartp) {
NVICDisableVector(USART2_IRQn);
NVICDisableVector(DMA1_Channel6_IRQn);
NVICDisableVector(DMA1_Channel7_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_6);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_7);
RCC->APB1ENR &= ~RCC_APB1ENR_USART2EN;
return;
}
@@ -576,7 +462,8 @@ void uart_lld_stop(UARTDriver *uartp) {
NVICDisableVector(USART3_IRQn);
NVICDisableVector(DMA1_Channel2_IRQn);
NVICDisableVector(DMA1_Channel3_IRQn);
- dmaDisable(DMA1_ID);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_2);
+ dmaRelease(STM32_DMA1_ID, STM32_DMA_CHANNEL_3);
RCC->APB1ENR &= ~RCC_APB1ENR_USART3EN;
return;
}
@@ -598,10 +485,10 @@ void uart_lld_stop(UARTDriver *uartp) {
void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
/* TX DMA channel preparation and start.*/
- dmaSetupChannel(uartp->ud_dmap, uartp->ud_dmatx, n, txbuf,
- uartp->ud_dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
+ dmaSetupChannel(uartp->dmap, uartp->dmatx, n, txbuf,
+ uartp->dmaccr | DMA_CCR1_DIR | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_TCIE);
- dmaEnableChannel(uartp->ud_dmap, uartp->ud_dmatx);
+ dmaEnableChannel(uartp->dmap, uartp->dmatx);
}
/**
@@ -617,9 +504,9 @@ void uart_lld_start_send(UARTDriver *uartp, size_t n, const void *txbuf) {
*/
size_t uart_lld_stop_send(UARTDriver *uartp) {
- dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmatx);
- dmaClearChannel(uartp->ud_dmap, uartp->ud_dmatx);
- return (size_t)uartp->ud_dmap->channels[uartp->ud_dmatx].CNDTR;
+ dmaDisableChannel(uartp->dmap, uartp->dmatx);
+ dmaClearChannel(uartp->dmap, uartp->dmatx);
+ return (size_t)uartp->dmap->channels[uartp->dmatx].CNDTR;
}
/**
@@ -636,14 +523,14 @@ size_t uart_lld_stop_send(UARTDriver *uartp) {
void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
/* Stopping previous activity (idle state).*/
- dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx);
- dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx);
+ dmaDisableChannel(uartp->dmap, uartp->dmarx);
+ dmaClearChannel(uartp->dmap, uartp->dmarx);
/* RX DMA channel preparation and start.*/
- dmaSetupChannel(uartp->ud_dmap, uartp->ud_dmarx, n, rxbuf,
- uartp->ud_dmaccr | DMA_CCR1_MINC |
+ dmaSetupChannel(uartp->dmap, uartp->dmarx, n, rxbuf,
+ uartp->dmaccr | DMA_CCR1_MINC |
DMA_CCR1_TEIE | DMA_CCR1_TCIE);
- dmaEnableChannel(uartp->ud_dmap, uartp->ud_dmarx);
+ dmaEnableChannel(uartp->dmap, uartp->dmarx);
}
/**
@@ -660,9 +547,9 @@ void uart_lld_start_receive(UARTDriver *uartp, size_t n, void *rxbuf) {
size_t uart_lld_stop_receive(UARTDriver *uartp) {
size_t n;
- dmaDisableChannel(uartp->ud_dmap, uartp->ud_dmarx);
- dmaClearChannel(uartp->ud_dmap, uartp->ud_dmarx);
- n = (size_t)uartp->ud_dmap->channels[uartp->ud_dmarx].CNDTR;
+ dmaDisableChannel(uartp->dmap, uartp->dmarx);
+ dmaClearChannel(uartp->dmap, uartp->dmarx);
+ n = (size_t)uartp->dmap->channels[uartp->dmarx].CNDTR;
set_rx_idle_loop(uartp);
return n;
}
diff --git a/os/hal/platforms/STM32/uart_lld.h b/os/hal/platforms/STM32/uart_lld.h
index 589a274fa..9321df85c 100644
--- a/os/hal/platforms/STM32/uart_lld.h
+++ b/os/hal/platforms/STM32/uart_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -68,21 +69,21 @@
/**
* @brief USART1 interrupt priority level setting.
*/
-#if !defined(STM32_UART_USART1_IRQ_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART1_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART1_IRQ_PRIORITY 12
#endif
/**
* @brief USART2 interrupt priority level setting.
*/
-#if !defined(STM32_UART_USART2_IRQ_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART2_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART2_IRQ_PRIORITY 12
#endif
/**
* @brief USART3 interrupt priority level setting.
*/
-#if !defined(STM32_UART_USART3_IRQ_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART3_IRQ_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART3_IRQ_PRIORITY 12
#endif
@@ -92,7 +93,7 @@
* because of the channels ordering the RX channel has always priority
* over the TX channel.
*/
-#if !defined(STM32_UART_USART1_DMA_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART1_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART1_DMA_PRIORITY 0
#endif
@@ -102,7 +103,7 @@
* because of the channels ordering the RX channel has always priority
* over the TX channel.
*/
-#if !defined(STM32_UART_USART2_DMA_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART2_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART2_DMA_PRIORITY 0
#endif
/**
@@ -111,35 +112,17 @@
* because of the channels ordering the RX channel has always priority
* over the TX channel.
*/
-#if !defined(STM32_UART_USART3_DMA_PRIO) || defined(__DOXYGEN__)
+#if !defined(STM32_UART_USART3_DMA_PRIORITY) || defined(__DOXYGEN__)
#define STM32_UART_USART3_DMA_PRIORITY 0
#endif
/**
* @brief USART1 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
+ * @note The default action for DMA errors is a system halt because DMA
+ * error can only happen because programming errors.
*/
-#if !defined(STM32_UART_USART1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_UART_USART1_DMA_ERROR_HOOK() chSysHalt()
-#endif
-
-/**
- * @brief USART2 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
- */
-#if !defined(STM32_UART_USART2_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_UART_USART2_DMA_ERROR_HOOK() chSysHalt()
-#endif
-
-/**
- * @brief USART3 DMA error hook.
- * @note The default action for DMA errors is a system halt because DMA error
- * can only happen because programming errors.
- */
-#if !defined(STM32_UART_USART3_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
-#define STM32_UART_USART3_DMA_ERROR_HOOK() chSysHalt()
+#if !defined(STM32_UART_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
+#define STM32_UART_DMA_ERROR_HOOK(uartp) chSysHalt()
#endif
/*===========================================================================*/
@@ -158,15 +141,15 @@
#error "USART3 not present in the selected device"
#endif
-#if STM32_UART_USE_UART4 && !STM32_HAS_UART4
-#error "UART4 not present in the selected device"
-#endif
-
#if !STM32_UART_USE_USART1 && !STM32_UART_USE_USART2 && \
- !STM32_UART_USE_USART3 && !STM32_UART_USE_UART4
+ !STM32_UART_USE_USART3
#error "UART driver activated but no USART/UART peripheral assigned"
#endif
+#if !defined(STM32_DMA_REQUIRED)
+#define STM32_DMA_REQUIRED
+#endif
+
/*===========================================================================*/
/* Driver data structures and types. */
/*===========================================================================*/
@@ -212,40 +195,40 @@ typedef struct {
/**
* @brief End of transmission buffer callback.
*/
- uartcb_t uc_txend1;
+ uartcb_t txend1_cb;
/**
* @brief Physical end of transmission callback.
*/
- uartcb_t uc_txend2;
+ uartcb_t txend2_cb;
/**
* @brief Receive buffer filled callback.
*/
- uartcb_t uc_rxend;
+ uartcb_t rxend_cb;
/**
* @brief Character received while out if the @p UART_RECEIVE state.
*/
- uartccb_t uc_rxchar;
+ uartccb_t rxchar_cb;
/**
* @brief Receive error callback.
*/
- uartecb_t uc_rxerr;
+ uartecb_t rxerr_cb;
/* End of the mandatory fields.*/
/**
* @brief Bit rate.
*/
- uint32_t uc_speed;
+ uint32_t speed;
/**
* @brief Initialization value for the CR1 register.
*/
- uint16_t uc_cr1;
+ uint16_t cr1;
/**
* @brief Initialization value for the CR2 register.
*/
- uint16_t uc_cr2;
+ uint16_t cr2;
/**
* @brief Initialization value for the CR3 register.
*/
- uint16_t uc_cr3;
+ uint16_t cr3;
} UARTConfig;
/**
@@ -255,19 +238,19 @@ struct UARTDriver {
/**
* @brief Driver state.
*/
- uartstate_t ud_state;
+ uartstate_t state;
/**
* @brief Transmitter state.
*/
- uarttxstate_t ud_txstate;
+ uarttxstate_t txstate;
/**
* @brief Receiver state.
*/
- uartrxstate_t ud_rxstate;
+ uartrxstate_t rxstate;
/**
* @brief Current configuration data.
*/
- const UARTConfig *ud_config;
+ const UARTConfig *config;
#if defined(UART_DRIVER_EXT_FIELDS)
UART_DRIVER_EXT_FIELDS
#endif
@@ -275,27 +258,27 @@ struct UARTDriver {
/**
* @brief Pointer to the USART registers block.
*/
- USART_TypeDef *ud_usart;
+ USART_TypeDef *usart;
/**
* @brief Pointer to the DMA registers block.
*/
- stm32_dma_t *ud_dmap;
+ stm32_dma_t *dmap;
/**
* @brief DMA priority bit mask.
*/
- uint32_t ud_dmaccr;
+ uint32_t dmaccr;
/**
* @brief Receive DMA channel.
*/
- uint8_t ud_dmarx;
+ uint8_t dmarx;
/**
* @brief Transmit DMA channel.
*/
- uint8_t ud_dmatx;
+ uint8_t dmatx;
/**
* @brief Default receive buffer while into @p UART_RX_IDLE state.
*/
- volatile uint16_t ud_rxbuf;
+ volatile uint16_t rxbuf;
};
/*===========================================================================*/
diff --git a/os/hal/platforms/STM32/usb_lld.c b/os/hal/platforms/STM32/usb_lld.c
index 3fe6771ea..331eb38c3 100644
--- a/os/hal/platforms/STM32/usb_lld.c
+++ b/os/hal/platforms/STM32/usb_lld.c
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -29,7 +30,6 @@
#include "ch.h"
#include "hal.h"
-#include "usb.h"
#if HAL_USE_USB || defined(__DOXYGEN__)
@@ -44,33 +44,123 @@
USBDriver USBD1;
#endif
-
/*===========================================================================*/
/* Driver local variables. */
/*===========================================================================*/
/**
* @brief EP0 state.
+ * @note It is an union because IN and OUT endpoints are never used at the
+ * same time for EP0.
*/
-static USBEndpointState ep0state;
+static union {
+ /**
+ * @brief IN EP0 state.
+ */
+ USBInEndpointState in;
+ /**
+ * @brief OUT EP0 state.
+ */
+ USBOutEndpointState out;
+} ep0_state;
/**
* @brief EP0 initialization structure.
*/
static const USBEndpointConfig ep0config = {
+ USB_EP_MODE_TYPE_CTRL | USB_EP_MODE_TRANSACTION,
+ _usb_ep0setup,
_usb_ep0in,
_usb_ep0out,
0x40,
0x40,
- EPR_EP_TYPE_CONTROL | EPR_STAT_TX_STALL | EPR_STAT_RX_VALID,
- 0x40,
- 0x80
+ &ep0_state.in,
+ &ep0_state.out
};
/*===========================================================================*/
/* Driver local functions. */
/*===========================================================================*/
+/**
+ * @brief Resets the packet memory allocator.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ */
+static void pm_reset(USBDriver *usbp) {
+
+ /* The first 64 bytes are reserved for the descriptors table. The effective
+ available RAM for endpoint buffers is just 448 bytes.*/
+ usbp->pmnext = 64;
+}
+
+/**
+ * @brief Resets the packet memory allocator.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] size size of the packet buffer to allocate
+ */
+static uint32_t pm_alloc(USBDriver *usbp, size_t size) {
+ uint32_t next;
+
+ next = usbp->pmnext;
+ usbp->pmnext += size;
+ chDbgAssert(usbp->pmnext > USB_PMA_SIZE, "pm_alloc(), #1", "PMA overflow");
+ return next;
+}
+
+/**
+ * @brief Copies a packet from memory into a packet buffer.
+ *
+ * @param[in] ep endpoint number
+ * @param[in] buf buffer where to fetch the endpoint data
+ * @param[in] n maximum number of bytes to copy
+ */
+static void write_packet(usbep_t ep, const uint8_t *buf, size_t n){
+ uint32_t *pmap;
+ stm32_usb_descriptor_t *udp;
+ size_t count;
+
+ udp = USB_GET_DESCRIPTOR(ep);
+ pmap = USB_ADDR2PTR(udp->TXADDR);
+ udp->TXCOUNT = n;
+ count = (n + 1) / 2;
+ while (count) {
+ *pmap++ = *(uint16_t *)buf;
+ buf += 2;
+ count--;
+ }
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
+}
+
+/**
+ * @brief Copies a packet from a packet buffer into memory.
+ *
+ * @param[in] ep endpoint number
+ * @param[in] buf buffer where to copy the endpoint data
+ * @param[in] n maximum number of bytes to copy
+ * @return The packet size.
+ * @retval 0 Special case, zero sized packet.
+ */
+static size_t read_packet(usbep_t ep, uint8_t *buf, size_t n){
+ uint32_t *pmap;
+ stm32_usb_descriptor_t *udp;
+ size_t count;
+
+ udp = USB_GET_DESCRIPTOR(ep);
+ pmap = USB_ADDR2PTR(udp->RXADDR);
+ count = udp->RXCOUNT & RXCOUNT_COUNT_MASK;
+ if (n > count)
+ n = count;
+ count = (n + 1) / 2;
+ while (count) {
+ *(uint16_t *)buf = (uint16_t)*pmap++;
+ buf += 2;
+ count--;
+ }
+ return n;
+}
+
/*===========================================================================*/
/* Driver interrupt handlers. */
/*===========================================================================*/
@@ -95,6 +185,7 @@ CH_IRQ_HANDLER(USB_HP_IRQHandler) {
*/
CH_IRQ_HANDLER(USB_LP_IRQHandler) {
uint32_t istr;
+ size_t n;
USBDriver *usbp = &USBD1;
CH_IRQ_PROLOGUE();
@@ -104,15 +195,40 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
/* USB bus reset condition handling.*/
if (istr & ISTR_RESET) {
_usb_reset(usbp);
- if (usbp->usb_config->uc_event_cb)
- usbp->usb_config->uc_event_cb(usbp, USB_EVENT_RESET);
+ _usb_isr_invoke_event_cb(usbp, USB_EVENT_RESET);
STM32_USB->ISTR = ~ISTR_RESET;
}
+ /* USB bus SUSPEND condition handling.*/
+ if (istr & ISTR_SUSP) {
+ STM32_USB->CNTR |= CNTR_FSUSP;
+ _usb_isr_invoke_event_cb(usbp, USB_EVENT_SUSPEND);
+#if STM32_USB_LOW_POWER_ON_SUSPEND
+ STM32_USB->CNTR |= CNTR_LP_MODE;
+#endif
+ STM32_USB->ISTR = ~ISTR_SUSP;
+ }
+
+ /* USB bus WAKEUP condition handling.*/
+ if (istr & ISTR_WKUP) {
+ uint32_t fnr = STM32_USB->FNR;
+ if (!(fnr & FNR_RXDP)) {
+ STM32_USB->CNTR &= ~CNTR_FSUSP;
+ _usb_isr_invoke_event_cb(usbp, USB_EVENT_WAKEUP);
+ }
+#if STM32_USB_LOW_POWER_ON_SUSPEND
+ else {
+ /* Just noise, going back in SUSPEND mode, reference manual 22.4.5,
+ table 169.*/
+ STM32_USB->CNTR |= CNTR_LP_MODE;
+ }
+#endif
+ STM32_USB->ISTR = ~ISTR_WKUP;
+ }
+
/* SOF handling.*/
if (istr & ISTR_SOF) {
- if (usbp->usb_config->uc_sof_cb)
- usbp->usb_config->uc_sof_cb(usbp);
+ _usb_isr_invoke_sof_cb(usbp);
STM32_USB->ISTR = ~ISTR_SOF;
}
@@ -120,19 +236,63 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
while (istr & ISTR_CTR) {
uint32_t ep;
uint32_t epr = STM32_USB->EPR[ep = istr & ISTR_EP_ID_MASK];
- const USBEndpointConfig *epcp = usbp->usb_ep[ep]->uep_config;
+ const USBEndpointConfig *epcp = usbp->epc[ep];
if (epr & EPR_CTR_TX) {
/* IN endpoint, transmission.*/
EPR_CLEAR_CTR_TX(ep);
- if (epcp->uepc_in_cb)
- epcp->uepc_in_cb(usbp, ep);
+ if (epcp->ep_mode & USB_EP_MODE_PACKET) {
+ /* Packet mode, just invokes the callback.*/
+ _usb_isr_invoke_in_cb(usbp, ep);
+ }
+ else {
+ /* Transaction mode.*/
+ n = USB_GET_DESCRIPTOR(ep)->TXCOUNT;
+ epcp->in_state->txbuf += n;
+ epcp->in_state->txcnt += n;
+ epcp->in_state->txsize -= n;
+ if (epcp->in_state->txsize > 0) {
+ /* Transfer not completed, there are more packets to send.*/
+ if (epcp->in_state->txsize > epcp->in_maxsize)
+ n = epcp->in_maxsize;
+ else
+ n = epcp->in_state->txsize;
+ write_packet(ep, epcp->in_state->txbuf, n);
+ }
+ else {
+ /* Transfer completed, invokes the callback.*/
+ _usb_isr_invoke_in_cb(usbp, ep);
+ }
+ }
}
if (epr & EPR_CTR_RX) {
- /* OUT endpoint, receive.*/
EPR_CLEAR_CTR_RX(ep);
- if (epcp->uepc_out_cb)
- epcp->uepc_out_cb(usbp, ep);
+ /* OUT endpoint, receive.*/
+ if (epr & EPR_SETUP) {
+ /* Setup packets handling, setup packets are handled using a
+ specific callback.*/
+ _usb_isr_invoke_setup_cb(usbp, ep);
+ }
+ else if (epcp->ep_mode & USB_EP_MODE_PACKET) {
+ /* Packet mode, just invokes the callback.*/
+ _usb_isr_invoke_out_cb(usbp, ep);
+ }
+ else {
+ /* Transaction mode.*/
+ n = read_packet(ep, epcp->out_state->rxbuf, epcp->out_state->rxsize);
+ epcp->out_state->rxbuf += n;
+ epcp->out_state->rxcnt += n;
+ epcp->out_state->rxsize -= n;
+ epcp->out_state->rxpkts -= 1;
+ if (epcp->out_state->rxpkts > 0) {
+ /* Transfer not completed, there are more packets to receive.*/
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
+ }
+ else {
+ /* Transfer completed, invokes the callback.*/
+ _usb_isr_invoke_out_cb(usbp, ep);
+ }
+ }
}
istr = STM32_USB->ISTR;
}
@@ -152,10 +312,6 @@ CH_IRQ_HANDLER(USB_LP_IRQHandler) {
*/
void usb_lld_init(void) {
- /* USB reset, ensures reset state in order to avoid trouble with JTAGs.*/
- RCC->APB1RSTR = RCC_APB1RSTR_USBRST;
- RCC->APB1RSTR = 0;
-
/* Driver initialization.*/
usbObjectInit(&USBD1);
}
@@ -169,7 +325,7 @@ void usb_lld_init(void) {
*/
void usb_lld_start(USBDriver *usbp) {
- if (usbp->usb_state == USB_STOP) {
+ if (usbp->state == USB_STOP) {
/* Clock activation.*/
#if STM32_USB_USE_USB1
if (&USBD1 == usbp) {
@@ -183,11 +339,12 @@ void usb_lld_start(USBDriver *usbp) {
CORTEX_PRIORITY_MASK(STM32_USB_USB1_HP_IRQ_PRIORITY));
NVICEnableVector(USB_LP_CAN1_RX0_IRQn,
CORTEX_PRIORITY_MASK(STM32_USB_USB1_LP_IRQ_PRIORITY));
-
- /* Reset procedure enforced on driver start.*/
- _usb_reset(&USBD1);
+ /* Releases the USB reset.*/
+ STM32_USB->CNTR = 0;
}
#endif
+ /* Reset procedure enforced on driver start.*/
+ _usb_reset(usbp);
}
/* Configuration.*/
}
@@ -202,11 +359,12 @@ void usb_lld_start(USBDriver *usbp) {
void usb_lld_stop(USBDriver *usbp) {
/* If in ready state then disables the USB clock.*/
- if (usbp->usb_state == USB_STOP) {
+ if (usbp->state == USB_STOP) {
#if STM32_ADC_USE_ADC1
if (&USBD1 == usbp) {
NVICDisableVector(USB_HP_CAN1_TX_IRQn);
NVICDisableVector(USB_LP_CAN1_RX0_IRQn);
+ STM32_USB->CNTR = CNTR_PDWN | CNTR_FRES;
RCC->APB1ENR &= ~RCC_APB1ENR_USBEN;
}
#endif
@@ -223,25 +381,23 @@ void usb_lld_stop(USBDriver *usbp) {
void usb_lld_reset(USBDriver *usbp) {
uint32_t cntr;
- /* Powers up the transceiver while holding the USB in reset state.*/
- STM32_USB->CNTR = CNTR_FRES;
-
- /* Releases the USB reset, BTABLE is reset to zero.*/
- STM32_USB->CNTR = 0;
+ /* Post reset initialization.*/
+ STM32_USB->BTABLE = 0;
STM32_USB->ISTR = 0;
STM32_USB->DADDR = DADDR_EF;
- cntr = /*CNTR_ESOFM | */ CNTR_RESETM | /*CNTR_SUSPM |*/
- /*CNTR_WKUPM | CNTR_ERRM | CNTR_PMAOVRM |*/ CNTR_CTRM;
+ cntr = /*CNTR_ESOFM | */ CNTR_RESETM | CNTR_SUSPM |
+ CNTR_WKUPM | /*CNTR_ERRM | CNTR_PMAOVRM |*/ CNTR_CTRM;
/* The SOF interrupt is only enabled if a callback is defined for
this service because it is an high rate source.*/
- if (usbp->usb_config->uc_sof_cb != NULL)
+ if (usbp->config->sof_cb != NULL)
cntr |= CNTR_SOFM;
STM32_USB->CNTR = cntr;
+ /* Resets the packet memory allocator.*/
+ pm_reset(usbp);
+
/* EP0 initialization.*/
- memset(&ep0state, 0, sizeof ep0state);
- ep0state.uep_config = &ep0config;
- usbp->usb_ep[0] = &ep0state;
+ usbp->epc[0] = &ep0config;
usb_lld_init_endpoint(usbp, 0);
}
@@ -249,14 +405,12 @@ void usb_lld_reset(USBDriver *usbp) {
* @brief Sets the USB address.
*
* @param[in] usbp pointer to the @p USBDriver object
- * @param[in] addr the USB address
*
* @notapi
*/
-void usb_lld_set_address(USBDriver *usbp, uint8_t addr) {
+void usb_lld_set_address(USBDriver *usbp) {
- (void)usbp;
- STM32_USB->DADDR = (uint32_t)addr | DADDR_EF;
+ STM32_USB->DADDR = (uint32_t)(usbp->address) | DADDR_EF;
}
/**
@@ -268,25 +422,55 @@ void usb_lld_set_address(USBDriver *usbp, uint8_t addr) {
* @notapi
*/
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
- uint16_t nblocks;
+ uint16_t nblocks, epr;
stm32_usb_descriptor_t *dp;
- const USBEndpointConfig *epcp = usbp->usb_ep[ep]->uep_config;
+ const USBEndpointConfig *epcp = usbp->epc[ep];
+
+ /* Setting the endpoint type.*/
+ switch (epcp->ep_mode & USB_EP_MODE_TYPE) {
+ case USB_EP_MODE_TYPE_ISOC:
+ epr = EPR_EP_TYPE_ISO;
+ break;
+ case USB_EP_MODE_TYPE_BULK:
+ epr = EPR_EP_TYPE_BULK;
+ break;
+ case USB_EP_MODE_TYPE_INTR:
+ epr = EPR_EP_TYPE_INTERRUPT;
+ break;
+ default:
+ epr = EPR_EP_TYPE_CONTROL;
+ }
+
+ /* IN endpoint settings, always in NAK mode initially.*/
+ if (epcp->in_cb != NULL)
+ epr |= EPR_STAT_TX_NAK;
+
+ /* OUT endpoint settings. If the endpoint is in packet mode then it must
+ start ready to accept data else it must start in NAK mode.*/
+ if (epcp->out_cb != NULL) {
+ if (epcp->ep_mode & USB_EP_MODE_PACKET) {
+ usbp->receiving |= (1 << ep);
+ epr |= EPR_STAT_RX_VALID;
+ }
+ else
+ epr |= EPR_STAT_RX_NAK;
+ }
/* EPxR register setup.*/
- EPR_SET(ep, epcp->uepc_epr | ep);
- EPR_TOGGLE(ep, epcp->uepc_epr);
+ EPR_SET(ep, epr | ep);
+ EPR_TOGGLE(ep, epr);
/* Endpoint size and address initialization.*/
- if (epcp->uepc_out_maxsize > 62)
- nblocks = (((((epcp->uepc_out_maxsize - 1) | 0x1f) + 1) / 32) << 10) |
+ if (epcp->out_maxsize > 62)
+ nblocks = (((((epcp->out_maxsize - 1) | 0x1f) + 1) / 32) << 10) |
0x8000;
else
- nblocks = ((((epcp->uepc_out_maxsize - 1) | 1) + 1) / 2) << 10;
+ nblocks = ((((epcp->out_maxsize - 1) | 1) + 1) / 2) << 10;
dp = USB_GET_DESCRIPTOR(ep);
dp->TXCOUNT = 0;
dp->RXCOUNT = nblocks;
- dp->TXADDR = epcp->uepc_inaddr;
- dp->RXADDR = epcp->uepc_outaddr;
+ dp->TXADDR = pm_alloc(usbp, epcp->in_maxsize);
+ dp->RXADDR = pm_alloc(usbp, epcp->out_maxsize);
}
/**
@@ -299,232 +483,275 @@ void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep) {
void usb_lld_disable_endpoints(USBDriver *usbp) {
unsigned i;
- (void)usbp;
+ /* Resets the packet memory allocator.*/
+ pm_reset(usbp);
+
+ /* Disabling all endpoints.*/
for (i = 1; i <= USB_ENDOPOINTS_NUMBER; i++) {
EPR_TOGGLE(i, 0);
EPR_SET(i, 0);
}
+}
+/**
+ * @brief Returns the status of an OUT endpoint.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
+ *
+ * @notapi
+ */
+usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
+
+ (void)usbp;
+ switch (STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) {
+ case EPR_STAT_RX_DIS:
+ return EP_STATUS_DISABLED;
+ case EPR_STAT_RX_STALL:
+ return EP_STATUS_STALLED;
+ default:
+ return EP_STATUS_ACTIVE;
+ }
}
/**
- * @brief Returns the number of bytes readable from the receive packet
- * buffer.
+ * @brief Returns the status of an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @return The number of bytes that are effectively available.
- * @retval 0 Data not yet available.
+ * @return The endpoint status.
+ * @retval EP_STATUS_DISABLED The endpoint is not active.
+ * @retval EP_STATUS_STALLED The endpoint is stalled.
+ * @retval EP_STATUS_ACTIVE The endpoint is active.
*
* @notapi
*/
-size_t usb_lld_get_readable(USBDriver *usbp, usbep_t ep) {
+usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
- if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_NAK)
- return 0;
- return (size_t)(USB_GET_DESCRIPTOR(ep)->RXCOUNT & RXCOUNT_COUNT_MASK);
+ switch (STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) {
+ case EPR_STAT_TX_DIS:
+ return EP_STATUS_DISABLED;
+ case EPR_STAT_TX_STALL:
+ return EP_STATUS_STALLED;
+ default:
+ return EP_STATUS_ACTIVE;
+ }
}
/**
- * @brief Endpoint read.
- * @details The buffered packet is copied into the user buffer and then
- * the endpoint is brought to the valid state in order to allow
- * reception of more data.
+ * @brief Reads a setup packet from the dedicated packet buffer.
+ * @details This function must be invoked in the context of the @p setup_cb
+ * callback in order to read the received setup packet.
+ * @pre In order to use this function the endpoint must have been
+ * initialized as a control endpoint.
+ * @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @param[out] buf buffer where to copy the endpoint data
- * @param[in] n maximum number of bytes to copy
- * @return The number of bytes that were effectively available.
- * @retval 0 Data not yet available.
+ * @param[out] buf buffer where to copy the packet data
*
* @notapi
*/
-size_t usb_lld_read(USBDriver *usbp, usbep_t ep, uint8_t *buf, size_t n) {
+void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf) {
uint32_t *pmap;
stm32_usb_descriptor_t *udp;
- size_t count;
+ uint32_t n;
(void)usbp;
- if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_NAK)
- return 0;
-
udp = USB_GET_DESCRIPTOR(ep);
pmap = USB_ADDR2PTR(udp->RXADDR);
- count = udp->RXCOUNT & RXCOUNT_COUNT_MASK;
- if (n > count)
- n = count;
- count = (n + 1) / 2;
- while (count) {
+ for (n = 0; n < 4; n++) {
*(uint16_t *)buf = (uint16_t)*pmap++;
buf += 2;
- count--;
}
EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
- return n;
}
+
/**
- * @brief Returns the number of bytes writeable to the transmit packet
- * buffer.
+ * @brief Reads a packet from the dedicated packet buffer.
+ * @pre In order to use this function he endpoint must have been
+ * initialized in packet mode.
+ * @post The endpoint is ready to accept another packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @return The number of bytes that can be written.
- * @retval 0 Endpoint not ready for transmission.
+ * @param[out] buf buffer where to copy the packet data
+ * @param[in] n maximum number of bytes to copy. This value must
+ * not exceed the maximum packet size for this endpoint.
+ * @return The received packet size regardless the specified
+ * @p n parameter.
+ * @retval 0 Zero size packet received.
*
- * @iclass
+ * @notapi
*/
-size_t usb_lld_get_writeable(USBDriver *usbp, usbep_t ep) {
+size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n) {
+ uint32_t *pmap;
+ stm32_usb_descriptor_t *udp;
+ size_t count;
- if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_NAK)
- return 0;
- return (size_t)usbp->usb_ep[ep]->uep_config->uepc_in_maxsize;
+ (void)usbp;
+ udp = USB_GET_DESCRIPTOR(ep);
+ pmap = USB_ADDR2PTR(udp->RXADDR);
+ count = udp->RXCOUNT & RXCOUNT_COUNT_MASK;
+ if (n > count)
+ n = count;
+ n = (n + 1) / 2;
+ while (n > 0) {
+ *(uint16_t *)buf = (uint16_t)*pmap++;
+ buf += 2;
+ n--;
+ }
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
+ return count;
}
/**
- * @brief Endpoint write.
- * @details The user data is copied in the packer memory and then
- * the endpoint is brought to the valid state in order to allow
- * transmission.
+ * @brief Writes a packet to the dedicated packet buffer.
+ * @pre In order to use this function he endpoint must have been
+ * initialized in packet mode.
+ * @post The endpoint is ready to transmit the packet.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
- * @param[in] buf buffer where to copy the endpoint data
- * @param[in] n maximum number of bytes to copy
- * @return The number of bytes that were effectively written.
- * @retval 0 Endpoint not ready for transmission.
+ * @param[in] buf buffer where to fetch the packet data
+ * @param[in] n maximum number of bytes to copy. This value must
+ * not exceed the maximum packet size for this endpoint.
*
* @notapi
*/
-size_t usb_lld_write(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf,
- size_t n) {
+void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n) {
uint32_t *pmap;
stm32_usb_descriptor_t *udp;
- size_t count;
(void)usbp;
- if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_NAK)
- return 0;
-
udp = USB_GET_DESCRIPTOR(ep);
pmap = USB_ADDR2PTR(udp->TXADDR);
udp->TXCOUNT = n;
- count = (n + 1) / 2;
- while (count) {
+ n = (n + 1) / 2;
+ while (n > 0) {
*pmap++ = *(uint16_t *)buf;
buf += 2;
- count--;
+ n--;
}
EPR_SET_STAT_TX(ep, EPR_STAT_TX_VALID);
- return n;
}
/**
- * @brief Returns the status of an IN endpoint.
+ * @brief Starts a receive operation on an OUT endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
+ * @param[out] buf buffer where to copy the endpoint data
+ * @param[in] n maximum number of bytes to copy in the buffer
*
* @notapi
*/
-usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep) {
-
- (void)usbp;
- switch (STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) {
- case EPR_STAT_TX_DIS:
- return EP_STATUS_DISABLED;
- case EPR_STAT_TX_STALL:
- return EP_STATUS_STALLED;
- default:
- return EP_STATUS_ACTIVE;
- }
+void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n) {
+ USBOutEndpointState *osp = usbp->epc[ep]->out_state;
+
+ osp->rxbuf = buf;
+ osp->rxsize = n;
+ osp->rxcnt = 0;
+ if (osp->rxsize == 0) /* Special case for zero sized packets.*/
+ osp->rxpkts = 1;
+ else
+ osp->rxpkts = (uint16_t)((n + usbp->epc[ep]->out_maxsize - 1) /
+ usbp->epc[ep]->out_maxsize);
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_VALID);
}
/**
- * @brief Returns the status of an OUT endpoint.
+ * @brief Starts a transmit operation on an IN endpoint.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
+ * @param[in] buf buffer where to fetch the endpoint data
+ * @param[in] n maximum number of bytes to copy
*
* @notapi
*/
-usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep) {
-
- (void)usbp;
- switch (STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) {
- case EPR_STAT_RX_DIS:
- return EP_STATUS_DISABLED;
- case EPR_STAT_RX_STALL:
- return EP_STATUS_STALLED;
- default:
- return EP_STATUS_ACTIVE;
- }
+void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n) {
+ USBInEndpointState *isp = usbp->epc[ep]->in_state;
+
+ isp->txbuf = buf;
+ isp->txsize = n;
+ isp->txcnt = 0;
+ if (n > (size_t)usbp->epc[ep]->in_maxsize)
+ n = (size_t)usbp->epc[ep]->in_maxsize;
+ write_packet(ep, buf, n);
}
/**
- * @brief Brings an IN endpoint in the stalled state.
+ * @brief Brings an OUT endpoint in the stalled state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
-void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
+void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
- EPR_SET_STAT_TX(ep, EPR_STAT_TX_STALL);
+ EPR_SET_STAT_RX(ep, EPR_STAT_RX_STALL);
}
/**
- * @brief Brings an OUT endpoint in the stalled state.
+ * @brief Brings an IN endpoint in the stalled state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
-void usb_lld_stall_out(USBDriver *usbp, usbep_t ep) {
+void usb_lld_stall_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
- EPR_SET_STAT_RX(ep, EPR_STAT_RX_STALL);
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_STALL);
}
/**
- * @brief Brings an IN endpoint in the active state.
+ * @brief Brings an OUT endpoint in the active state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
-void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
+void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
(void)usbp;
/* Makes sure to not put to NAK an endpoint that is already
transferring.*/
- if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_VALID)
- EPR_SET_STAT_TX(ep, EPR_STAT_TX_NAK);
+ if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_VALID)
+ EPR_SET_STAT_TX(ep, EPR_STAT_RX_NAK);
}
/**
- * @brief Brings an OUT endpoint in the active state.
+ * @brief Brings an IN endpoint in the active state.
*
* @param[in] usbp pointer to the @p USBDriver object
* @param[in] ep endpoint number
*
* @notapi
*/
-void usb_lld_clear_out(USBDriver *usbp, usbep_t ep) {
+void usb_lld_clear_in(USBDriver *usbp, usbep_t ep) {
(void)usbp;
/* Makes sure to not put to NAK an endpoint that is already
transferring.*/
- if ((STM32_USB->EPR[ep] & EPR_STAT_RX_MASK) != EPR_STAT_RX_VALID)
- EPR_SET_STAT_TX(ep, EPR_STAT_RX_NAK);
+ if ((STM32_USB->EPR[ep] & EPR_STAT_TX_MASK) != EPR_STAT_TX_VALID)
+ EPR_SET_STAT_TX(ep, EPR_STAT_TX_NAK);
}
#endif /* HAL_USE_USB */
diff --git a/os/hal/platforms/STM32/usb_lld.h b/os/hal/platforms/STM32/usb_lld.h
index e21bbecd2..9b5e9dad2 100644
--- a/os/hal/platforms/STM32/usb_lld.h
+++ b/os/hal/platforms/STM32/usb_lld.h
@@ -1,5 +1,6 @@
/*
- ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.
+ ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010,
+ 2011 Giovanni Di Sirio.
This file is part of ChibiOS/RT.
@@ -41,6 +42,11 @@
*/
#define USB_MAX_ENDPOINTS USB_ENDOPOINTS_NUMBER
+/**
+ * @brief This device requires the address change after the status packet.
+ */
+#define USB_SET_ADDRESS_MODE USB_LATE_SET_ADDRESS
+
/*===========================================================================*/
/* Driver pre-compile time settings. */
/*===========================================================================*/
@@ -55,6 +61,13 @@
#endif
/**
+ * @brief Enables the USB device low power mode on suspend.
+ */
+#if !defined(STM32_USB_LOW_POWER_ON_SUSPEND) || defined(__DOXYGEN__)
+#define STM32_USB_LOW_POWER_ON_SUSPEND FALSE
+#endif
+
+/**
* @brief USB1 interrupt priority level setting.
*/
#if !defined(STM32_USB_USB1_HP_IRQ_PRIORITY) || defined(__DOXYGEN__)
@@ -89,84 +102,105 @@
/*===========================================================================*/
/**
- * @brief Type of an USB Endpoint configuration structure.
- * @note Platform specific restrictions may apply to endpoints.
+ * @brief Type of an endpoint state structure.
*/
typedef struct {
/**
- * @brief IN endpoint notification callback.
+ * @brief Pointer to the transmission buffer.
*/
- usbepcallback_t uepc_in_cb;
+ const uint8_t *txbuf;
/**
- * @brief OUT endpoint notification callback.
+ * @brief Requested transmit transfer size.
*/
- usbepcallback_t uepc_out_cb;
+ size_t txsize;
/**
- * @brief IN endpoint maximum packet size.
+ * @brief Transmitted bytes so far.
*/
- uint16_t uepc_in_maxsize;
+ size_t txcnt;
+} USBInEndpointState;
+
+/**
+ * @brief Type of an endpoint state structure.
+ */
+typedef struct {
/**
- * @brief OUT endpoint maximum packet size.
+ * @brief Number of packets to receive.
*/
- uint16_t uepc_out_maxsize;
- /* End of the mandatory fields.*/
+ uint16_t rxpkts;
/**
- * @brief EPxR register initialization value.
- * @note Do not specify the EA field, leave it to zero.
+ * @brief Pointer to the receive buffer.
*/
- uint16_t uepc_epr;
+ uint8_t *rxbuf;
/**
- * @brief Endpoint IN buffer address as offset in the PMA.
+ * @brief Requested receive transfer size.
*/
- uint16_t uepc_inaddr;
+ size_t rxsize;
/**
- * @brief Endpoint OUT buffer address as offset in the PMA.
+ * @brief Received bytes so far.
*/
- uint16_t uepc_outaddr;
-} USBEndpointConfig;
-
+ size_t rxcnt;
+} USBOutEndpointState;
/**
- * @brief Type of an endpoint state structure.
+ * @brief Type of an USB endpoint configuration structure.
+ * @note Platform specific restrictions may apply to endpoints.
*/
typedef struct {
/**
- * @brief Configuration associated to the endpoint.
+ * @brief Type and mode of the endpoint.
*/
- const USBEndpointConfig *uep_config;
+ uint32_t ep_mode;
/**
- * @brief Pointer to the transmission buffer.
+ * @brief Setup packet notification callback.
+ * @details This callback is invoked when a setup packet has been
+ * received.
+ * @post The application must immediately call @p usbReadPacket() in
+ * order to access the received packet.
+ * @note This field is only valid for @p USB_EP_MODE_TYPE_CTRL
+ * endpoints, it should be set to @p NULL for other endpoint
+ * types.
*/
- const uint8_t *uep_txbuf;
+ usbepcallback_t setup_cb;
/**
- * @brief Pointer to the receive buffer.
+ * @brief IN endpoint notification callback.
+ * @details This field must be set to @p NULL if the IN endpoint is not
+ * used.
*/
- uint8_t *uep_rxbuf;
+ usbepcallback_t in_cb;
/**
- * @brief Requested transmit transfer size.
+ * @brief OUT endpoint notification callback.
+ * @details This field must be set to @p NULL if the OUT endpoint is not
+ * used.
*/
- size_t uep_txsize;
- /**
- * @brief Requested receive transfer size.
- */
- size_t uep_rxsize;
+ usbepcallback_t out_cb;
/**
- * @brief Transmitted bytes so far.
+ * @brief IN endpoint maximum packet size.
+ * @details This field must be set to zero if the IN endpoint is not
+ * used.
*/
- size_t uep_txcnt;
+ uint16_t in_maxsize;
/**
- * @brief Received bytes so far.
- */
- size_t uep_rxcnt;
+ * @brief OUT endpoint maximum packet size.
+ * @details This field must be set to zero if the OUT endpoint is not
+ * used.
+ */
+ uint16_t out_maxsize;
/**
- * @brief @p TRUE if transmitting else @p FALSE.
+ * @brief @p USBEndpointState associated to the IN endpoint.
+ * @details This structure maintains the state of the IN endpoint when
+ * the endpoint is not in packet mode. Endpoints configured in
+ * packet mode must set this field to @p NULL.
*/
- uint8_t uep_transmitting;
+ USBInEndpointState *in_state;
/**
- * @brief @p TRUE if receiving else @p FALSE.
+ * @brief @p USBEndpointState associated to the OUT endpoint.
+ * @details This structure maintains the state of the OUT endpoint when
+ * the endpoint is not in packet mode. Endpoints configured in
+ * packet mode must set this field to @p NULL.
*/
- uint8_t uep_receiving;
-} USBEndpointState;
+ USBOutEndpointState *out_state;
+ /* End of the mandatory fields.*/
+} USBEndpointConfig;
/**
* @brief Type of an USB driver configuration structure.
@@ -176,22 +210,22 @@ typedef struct {
* @brief USB events callback.
* @details This callback is invoked when an USB driver event is registered.
*/
- usbeventcb_t uc_event_cb;
+ usbeventcb_t event_cb;
/**
* @brief Device GET_DESCRIPTOR request callback.
* @note This callback is mandatory and cannot be set to @p NULL.
*/
- usbgetdescriptor_t uc_get_descriptor_cb;
+ usbgetdescriptor_t get_descriptor_cb;
/**
* @brief Requests hook callback.
* @details This hook allows to be notified of standard requests or to
* handle non standard requests.
*/
- usbreqhandler_t uc_requests_hook_cb;
+ usbreqhandler_t requests_hook_cb;
/**
* @brief Start Of Frame callback.
*/
- usbcallback_t uc_sof_cb;
+ usbcallback_t sof_cb;
/* End of the mandatory fields.*/
} USBConfig;
@@ -202,61 +236,68 @@ struct USBDriver {
/**
* @brief Driver state.
*/
- usbstate_t usb_state;
+ usbstate_t state;
/**
* @brief Current configuration data.
*/
- const USBConfig *usb_config;
+ const USBConfig *config;
/**
* @brief Field available to user, it can be used to associate an
* application-defined handler to the USB driver.
*/
- void *usb_param;
+ void *param;
/**
- * @brief Active endpoints configurations.
+ * @brief Bit map of the transmitting IN endpoints.
*/
- USBEndpointState *usb_ep[USB_MAX_ENDPOINTS + 1];
+ uint16_t transmitting;
/**
- * @brief Endpoint 0 state.
+ * @brief Bit map of the receiving OUT endpoints.
*/
- usbep0state_t usb_ep0state;
+ uint16_t receiving;
/**
- * @brief Next position in the buffer to be transferred through endpoint 0.
+ * @brief Active endpoints configurations.
*/
- uint8_t *usb_ep0next;
+ const USBEndpointConfig *epc[USB_MAX_ENDPOINTS + 1];
/**
- * @brief Maximum number of bytes to be tranferred through endpoint 0.
+ * @brief Endpoint 0 state.
*/
- size_t usb_ep0max;
+ usbep0state_t ep0state;
/**
- * @brief Number of bytes yet to be tranferred through endpoint 0.
+ * @brief Next position in the buffer to be transferred through endpoint 0.
*/
- size_t usb_ep0n;
+ uint8_t *ep0next;
/**
- * @brief Size of the last packet transferred through endpoint 0.
+ * @brief Number of bytes yet to be transferred through endpoint 0.
*/
- size_t usb_ep0lastsize;
+ size_t ep0n;
/**
* @brief Endpoint 0 end transaction callback.
*/
- usbcallback_t usb_ep0endcb;
+ usbcallback_t ep0endcb;
/**
* @brief Setup packet buffer.
*/
- uint8_t usb_setup[8];
+ uint8_t setup[8];
/**
* @brief Current USB device status.
*/
- uint16_t usb_status;
+ uint16_t status;
/**
* @brief Assigned USB address.
*/
- uint8_t usb_address;
+ uint8_t address;
/**
* @brief Current USB device configuration.
*/
- uint8_t usb_configuration;
+ uint8_t configuration;
+#if defined(USB_DRIVER_EXT_FIELDS)
+ USB_DRIVER_EXT_FIELDS
+#endif
/* End of the mandatory fields.*/
+ /**
+ * @brief Pointer to the next address in the packet memory.
+ */
+ uint32_t pmnext;
};
/*===========================================================================*/
@@ -270,7 +311,7 @@ struct USBDriver {
*
* @notapi
*/
-#define usb_lld_fetch_word(p) (*(uint16_t *)p)
+#define usb_lld_fetch_word(p) (*(uint16_t *)(p))
/**
* @brief Returns the current frame number.
@@ -282,6 +323,37 @@ struct USBDriver {
*/
#define usb_lld_get_frame_number(usbp) (STM32_USB->FNR & FNR_FN_MASK)
+/**
+ * @brief Returns the exact size of a receive transaction.
+ * @details The received size can be different from the size specified in
+ * @p usbStartReceiveI() because the last packet could have a size
+ * different from the expected one.
+ * @pre The OUT endpoint must have been configured in transaction mode
+ * in order to use this function.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return Received data size.
+ *
+ * @notapi
+ */
+#define usb_lld_get_transaction_size(usbp, ep) \
+ ((usbp)->epc[ep]->out_state->rxcnt)
+
+/**
+ * @brief Returns the exact size of a received packet.
+ * @pre The OUT endpoint must have been configured in packet mode
+ * in order to use this function.
+ *
+ * @param[in] usbp pointer to the @p USBDriver object
+ * @param[in] ep endpoint number
+ * @return Received data size.
+ *
+ * @notapi
+ */
+#define usb_lld_get_packet_size(usbp, ep) \
+ ((size_t)USB_GET_DESCRIPTOR(ep)->RXCOUNT & RXCOUNT_COUNT_MASK)
+
/*===========================================================================*/
/* External declarations. */
/*===========================================================================*/
@@ -290,14 +362,6 @@ struct USBDriver {
extern USBDriver USBD1;
#endif
-#if !defined(__DOXYGEN__)
-extern const USBEndpointConfig usb_lld_ep0config;
-#endif
-
-#if !defined(__DOXYGEN__)
-extern USBEndpointState usb_lld_ep0state;
-#endif
-
#ifdef __cplusplus
extern "C" {
#endif
@@ -305,20 +369,24 @@ extern "C" {
void usb_lld_start(USBDriver *usbp);
void usb_lld_stop(USBDriver *usbp);
void usb_lld_reset(USBDriver *usbp);
- void usb_lld_set_address(USBDriver *usbp, uint8_t addr);
+ void usb_lld_set_address(USBDriver *usbp);
void usb_lld_init_endpoint(USBDriver *usbp, usbep_t ep);
void usb_lld_disable_endpoints(USBDriver *usbp);
- size_t usb_lld_get_readable(USBDriver *usbp, usbep_t ep);
- size_t usb_lld_read(USBDriver *usbp, usbep_t ep,
- uint8_t *buf, size_t n);
- size_t usb_lld_write(USBDriver *usbp, usbep_t ep,
- const uint8_t *buf, size_t n);
usbepstatus_t usb_lld_get_status_in(USBDriver *usbp, usbep_t ep);
usbepstatus_t usb_lld_get_status_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_read_setup(USBDriver *usbp, usbep_t ep, uint8_t *buf);
+ size_t usb_lld_read_packet(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n);
+ void usb_lld_write_packet(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n);
+ void usb_lld_start_out(USBDriver *usbp, usbep_t ep,
+ uint8_t *buf, size_t n);
+ void usb_lld_start_in(USBDriver *usbp, usbep_t ep,
+ const uint8_t *buf, size_t n);
void usb_lld_stall_in(USBDriver *usbp, usbep_t ep);
void usb_lld_stall_out(USBDriver *usbp, usbep_t ep);
- void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
void usb_lld_clear_out(USBDriver *usbp, usbep_t ep);
+ void usb_lld_clear_in(USBDriver *usbp, usbep_t ep);
#ifdef __cplusplus
}
#endif