git-svn-id: svn://svn.code.sf.net/p/chibios/svn/trunk@1315 35acf78f-673a-0410-8e92-d51de3d6d3f4
parent
a943eaecc7
commit
2ab27d3c01
13
os/io/adc.c
13
os/io/adc.c
|
@ -45,6 +45,9 @@ void adcObjectInit(ADCDriver *adcp) {
|
||||||
adcp->ad_state = ADC_STOP;
|
adcp->ad_state = ADC_STOP;
|
||||||
adcp->ad_config = NULL;
|
adcp->ad_config = NULL;
|
||||||
adcp->ad_callback = NULL;
|
adcp->ad_callback = NULL;
|
||||||
|
adcp->ad_samples = NULL;
|
||||||
|
adcp->ad_depth = 0;
|
||||||
|
adcp->ad_grpp = NULL;
|
||||||
chSemInit(&adcp->ad_sem, 0);
|
chSemInit(&adcp->ad_sem, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,7 +122,7 @@ void adcStop(ADCDriver *adcp) {
|
||||||
*/
|
*/
|
||||||
bool_t adcStartConversion(ADCDriver *adcp,
|
bool_t adcStartConversion(ADCDriver *adcp,
|
||||||
ADCConversionGroup *grpp,
|
ADCConversionGroup *grpp,
|
||||||
void *samples,
|
adcsample_t *samples,
|
||||||
size_t depth,
|
size_t depth,
|
||||||
adccallback_t callback) {
|
adccallback_t callback) {
|
||||||
|
|
||||||
|
@ -137,7 +140,10 @@ bool_t adcStartConversion(ADCDriver *adcp,
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
adcp->ad_callback = callback;
|
adcp->ad_callback = callback;
|
||||||
adc_lld_start_conversion(adcp, grpp, samples, depth);
|
adcp->ad_samples = samples;
|
||||||
|
adcp->ad_depth = depth;
|
||||||
|
adcp->ad_grpp = grpp;
|
||||||
|
adc_lld_start_conversion(adcp);
|
||||||
adcp->ad_state = ADC_RUNNING;
|
adcp->ad_state = ADC_RUNNING;
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
@ -157,8 +163,11 @@ void adcStopConversion(ADCDriver *adcp) {
|
||||||
(adcp->ad_state == ADC_RUNNING),
|
(adcp->ad_state == ADC_RUNNING),
|
||||||
"adcStopConversion(), #1",
|
"adcStopConversion(), #1",
|
||||||
"invalid state");
|
"invalid state");
|
||||||
|
if (adcp->ad_state == ADC_RUNNING) {
|
||||||
adc_lld_stop_conversion(adcp);
|
adc_lld_stop_conversion(adcp);
|
||||||
|
adcp->ad_grpp = NULL;
|
||||||
adcp->ad_state = ADC_READY;
|
adcp->ad_state = ADC_READY;
|
||||||
|
}
|
||||||
chSysUnlock();
|
chSysUnlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@ typedef enum {
|
||||||
ADC_UNINIT = 0, /**< @brief Not initialized. */
|
ADC_UNINIT = 0, /**< @brief Not initialized. */
|
||||||
ADC_STOP = 1, /**< @brief Stopped. */
|
ADC_STOP = 1, /**< @brief Stopped. */
|
||||||
ADC_READY = 2, /**< @brief Ready. */
|
ADC_READY = 2, /**< @brief Ready. */
|
||||||
ADC_RUNNING = 3 /**< @brief Conversion complete.*/
|
ADC_RUNNING = 3 /**< @brief Conversion running. */
|
||||||
} adcstate_t;
|
} adcstate_t;
|
||||||
|
|
||||||
#include "adc_lld.h"
|
#include "adc_lld.h"
|
||||||
|
@ -52,7 +52,7 @@ extern "C" {
|
||||||
void adcStop(ADCDriver *adcp);
|
void adcStop(ADCDriver *adcp);
|
||||||
bool_t adcStartConversion(ADCDriver *adcp,
|
bool_t adcStartConversion(ADCDriver *adcp,
|
||||||
ADCConversionGroup *grpp,
|
ADCConversionGroup *grpp,
|
||||||
void *samples,
|
adcsample_t *samples,
|
||||||
size_t depth,
|
size_t depth,
|
||||||
adccallback_t callback);
|
adccallback_t callback);
|
||||||
void adcStopConversion(ADCDriver *adcp);
|
void adcStopConversion(ADCDriver *adcp);
|
||||||
|
|
|
@ -29,11 +29,19 @@
|
||||||
#include <stm32_dma.h>
|
#include <stm32_dma.h>
|
||||||
#include <nvic.h>
|
#include <nvic.h>
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if USE_STM32_ADC1 || defined(__DOXYGEN__)
|
#if USE_STM32_ADC1 || defined(__DOXYGEN__)
|
||||||
/** @brief ADC1 driver identifier.*/
|
/** @brief ADC1 driver identifier.*/
|
||||||
ADCDriver ADCD1;
|
ADCDriver ADCD1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver local variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Low Level Driver local functions. */
|
/* Low Level Driver local functions. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -47,13 +55,43 @@ ADCDriver ADCD1;
|
||||||
* @brief ADC1 DMA interrupt handler (channel 1).
|
* @brief ADC1 DMA interrupt handler (channel 1).
|
||||||
*/
|
*/
|
||||||
CH_IRQ_HANDLER(Vector6C) {
|
CH_IRQ_HANDLER(Vector6C) {
|
||||||
|
uint32_t isr;
|
||||||
|
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
if ((DMA1->ISR & DMA_ISR_TEIF1) != 0)
|
isr = DMA1->ISR;
|
||||||
STM32_ADC1_DMA_ERROR_HOOK();
|
if ((isr & DMA_ISR_HTIF1) != 0) {
|
||||||
|
/* Half transfer processing.*/
|
||||||
|
if (ADCD1.ad_callback != NULL) {
|
||||||
|
/* Invokes the callback passing the 1st half of the buffer.*/
|
||||||
|
ADCD1.ad_callback(ADCD1.ad_samples, ADCD1.ad_depth / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((isr & DMA_ISR_TCIF1) != 0) {
|
||||||
|
/* Transfer complete processing.*/
|
||||||
|
if (!ADCD1.ad_grpp->acg_circular) {
|
||||||
|
/* End conversion.*/
|
||||||
|
adc_lld_stop_conversion(&ADCD1);
|
||||||
|
ADCD1.ad_grpp = NULL;
|
||||||
|
ADCD1.ad_state = ADC_READY;
|
||||||
|
chSemResetI(&ADCD1.ad_sem, 0);
|
||||||
|
}
|
||||||
|
/* Callback handling.*/
|
||||||
|
if (ADCD1.ad_callback != NULL) {
|
||||||
|
if (ADCD1.ad_depth > 1) {
|
||||||
|
/* Invokes the callback passing the 2nd half of the buffer.*/
|
||||||
|
size_t half = ADCD1.ad_depth / 2;
|
||||||
|
ADCD1.ad_callback(ADCD1.ad_samples + half, half);
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
/* */
|
/* Invokes the callback passing the while buffer.*/
|
||||||
|
ADCD1.ad_callback(ADCD1.ad_samples, ADCD1.ad_depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((isr & DMA_ISR_TEIF1) != 0) {
|
||||||
|
/* DMA error processing.*/
|
||||||
|
STM32_ADC1_DMA_ERROR_HOOK();
|
||||||
}
|
}
|
||||||
DMA1->IFCR |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 |
|
DMA1->IFCR |= DMA_IFCR_CGIF1 | DMA_IFCR_CTCIF1 |
|
||||||
DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;
|
DMA_IFCR_CHTIF1 | DMA_IFCR_CTEIF1;
|
||||||
|
@ -72,10 +110,28 @@ CH_IRQ_HANDLER(Vector6C) {
|
||||||
void adc_lld_init(void) {
|
void adc_lld_init(void) {
|
||||||
|
|
||||||
#if USE_STM32_ADC1
|
#if USE_STM32_ADC1
|
||||||
|
/* Driver initialization.*/
|
||||||
adcObjectInit(&ADCD1);
|
adcObjectInit(&ADCD1);
|
||||||
ADCD1.ad_adc = ADC1;
|
ADCD1.ad_adc = ADC1;
|
||||||
ADCD1.ad_dma = DMA1_Channel1;
|
ADCD1.ad_dma = DMA1_Channel1;
|
||||||
ADCD1.ad_dmaprio = STM32_ADC1_DMA_PRIORITY << 12;
|
ADCD1.ad_dmaprio = STM32_ADC1_DMA_PRIORITY << 12;
|
||||||
|
|
||||||
|
/* Temporary activation.*/
|
||||||
|
ADC1->CR1 = 0;
|
||||||
|
ADC1->CR2 = ADC_CR2_ADON;
|
||||||
|
|
||||||
|
/* Reset calibration just to be safe.*/
|
||||||
|
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_RSTCAL;
|
||||||
|
while ((ADC1->CR2 & ADC_CR2_RSTCAL) != 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Calibration.*/
|
||||||
|
ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CAL;
|
||||||
|
while ((ADC1->CR2 & ADC_CR2_CAL) != 0)
|
||||||
|
;
|
||||||
|
|
||||||
|
/* Return the ADC in low power mode.*/
|
||||||
|
ADC1->CR2 = 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,8 +146,8 @@ void adc_lld_start(ADCDriver *adcp) {
|
||||||
if (adcp->ad_state == ADC_STOP) {
|
if (adcp->ad_state == ADC_STOP) {
|
||||||
#if USE_STM32_ADC1
|
#if USE_STM32_ADC1
|
||||||
if (&ADCD1 == adcp) {
|
if (&ADCD1 == adcp) {
|
||||||
|
dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
|
||||||
NVICEnableVector(DMA1_Channel1_IRQn, STM32_ADC1_IRQ_PRIORITY);
|
NVICEnableVector(DMA1_Channel1_IRQn, STM32_ADC1_IRQ_PRIORITY);
|
||||||
dmaEnable(DMA1_ID);
|
|
||||||
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
|
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
|
||||||
/* RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE) |
|
/* RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_ADCPRE) |
|
||||||
adcp->ad_config->ac_prescaler;*/
|
adcp->ad_config->ac_prescaler;*/
|
||||||
|
@ -99,19 +155,10 @@ void adc_lld_start(ADCDriver *adcp) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ADC activation.*/
|
/* ADC activation, the calibration procedure has already been performed
|
||||||
adcp->ad_adc->CR1 = 0;
|
during initialization.*/
|
||||||
|
adcp->ad_adc->CR1 = ADC_CR1_SCAN;
|
||||||
adcp->ad_adc->CR2 = ADC_CR2_ADON;
|
adcp->ad_adc->CR2 = ADC_CR2_ADON;
|
||||||
|
|
||||||
/* Reset calibration just to be safe.*/
|
|
||||||
adcp->ad_adc->CR2 |= ADC_CR2_RSTCAL;
|
|
||||||
while ((adcp->ad_adc->CR2 & ADC_CR2_RSTCAL) != 0)
|
|
||||||
;
|
|
||||||
|
|
||||||
/* Calibration.*/
|
|
||||||
adcp->ad_adc->CR2 |= ADC_CR2_CAL;
|
|
||||||
while ((adcp->ad_adc->CR2 & ADC_CR2_CAL) != 0)
|
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +177,6 @@ void adc_lld_stop(ADCDriver *adcp) {
|
||||||
ADC1->CR2 = 0;
|
ADC1->CR2 = 0;
|
||||||
NVICDisableVector(DMA1_Channel1_IRQn);
|
NVICDisableVector(DMA1_Channel1_IRQn);
|
||||||
dmaDisable(DMA1_ID);
|
dmaDisable(DMA1_ID);
|
||||||
/* RCC->CFGR &= ~RCC_CFGR_ADCPRE;*/
|
|
||||||
RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN;
|
RCC->APB2ENR &= ~RCC_APB2ENR_ADC1EN;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -141,35 +187,27 @@ void adc_lld_stop(ADCDriver *adcp) {
|
||||||
* @brief Starts an ADC conversion.
|
* @brief Starts an ADC conversion.
|
||||||
*
|
*
|
||||||
* @param[in] adcp pointer to the @p ADCDriver object
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
* @param[in] grpp pointer to a @p ADCConversionGroup object
|
|
||||||
* @param[out] samples pointer to the samples buffer
|
|
||||||
* @param[in] depth buffer depth (matrix rows number). The buffer depth
|
|
||||||
* must be one or an even number.
|
|
||||||
*
|
|
||||||
* @note The buffer is organized as a matrix of M*N elements where M is the
|
|
||||||
* channels number configured into the conversion group and N is the
|
|
||||||
* buffer depth. The samples are sequentially written into the buffer
|
|
||||||
* with no gaps.
|
|
||||||
*/
|
*/
|
||||||
void adc_lld_start_conversion(ADCDriver *adcp,
|
void adc_lld_start_conversion(ADCDriver *adcp) {
|
||||||
ADCConversionGroup *grpp,
|
uint32_t ccr, n;
|
||||||
void *samples,
|
ADCConversionGroup *grpp = adcp->ad_grpp;
|
||||||
size_t depth) {
|
|
||||||
|
|
||||||
/* DMA setup.*/
|
/* DMA setup.*/
|
||||||
adcp->ad_dma->CMAR = (uint32_t)samples;
|
adcp->ad_dma->CMAR = (uint32_t)adcp->ad_samples;
|
||||||
if (depth > 1) {
|
ccr = adcp->ad_dmaprio | DMA_CCR1_EN | DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 |
|
||||||
adcp->ad_dma->CNDTR = (uint32_t)grpp->acg_num_channels * (uint32_t)depth;
|
DMA_CCR1_MINC | DMA_CCR1_TCIE | DMA_CCR1_TEIE;
|
||||||
adcp->ad_dma->CCR = adcp->ad_dmaprio |
|
if (grpp->acg_circular)
|
||||||
DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 | DMA_CCR1_MINC |
|
ccr |= DMA_CCR1_CIRC;
|
||||||
DMA_CCR1_TCIE | DMA_CCR1_TEIE | DMA_CCR1_HTIE;
|
if (adcp->ad_depth > 1) {
|
||||||
}
|
/* If the buffer depth is greater than one then the half transfer interrupt
|
||||||
else {
|
interrupt is enabled in order to allows streaming processing.*/
|
||||||
adcp->ad_dma->CNDTR = (uint32_t)grpp->acg_num_channels;
|
ccr |= DMA_CCR1_HTIE;
|
||||||
adcp->ad_dma->CCR = adcp->ad_dmaprio |
|
n = (uint32_t)grpp->acg_num_channels * (uint32_t)adcp->ad_depth;
|
||||||
DMA_CCR1_MSIZE_0 | DMA_CCR1_PSIZE_0 | DMA_CCR1_MINC |
|
|
||||||
DMA_CCR1_TCIE | DMA_CCR1_TEIE;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
n = (uint32_t)grpp->acg_num_channels;
|
||||||
|
adcp->ad_dma->CNDTR = n;
|
||||||
|
adcp->ad_dma->CCR = ccr;
|
||||||
|
|
||||||
/* ADC setup.*/
|
/* ADC setup.*/
|
||||||
adcp->ad_adc->SMPR1 = grpp->acg_smpr1;
|
adcp->ad_adc->SMPR1 = grpp->acg_smpr1;
|
||||||
|
|
|
@ -63,6 +63,8 @@
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief ADC1 DMA error hook.
|
* @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.
|
||||||
*/
|
*/
|
||||||
#if !defined(STM32_ADC1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
#if !defined(STM32_ADC1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||||
#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()
|
#define STM32_ADC1_DMA_ERROR_HOOK() chSysHalt()
|
||||||
|
@ -99,6 +101,11 @@ typedef void (*adccallback_t)(adcsample_t *buffer, size_t n);
|
||||||
* operation.
|
* operation.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief Enables the circular buffer mode for the group.
|
||||||
|
*/
|
||||||
|
bool_t acg_circular;
|
||||||
|
/* End of the mandatory fields.*/
|
||||||
/**
|
/**
|
||||||
* @brief Number of the analog channels belonging to the conversion group.
|
* @brief Number of the analog channels belonging to the conversion group.
|
||||||
*/
|
*/
|
||||||
|
@ -140,6 +147,7 @@ typedef struct {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Driver configuration structure.
|
* @brief Driver configuration structure.
|
||||||
|
* @note It could be empty on some architectures.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
/* * <----------
|
/* * <----------
|
||||||
|
@ -164,13 +172,25 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
const ADCConfig *ad_config;
|
const ADCConfig *ad_config;
|
||||||
/**
|
/**
|
||||||
* @brief Semaphore for completion synchronization.
|
* @brief Synchronization semaphore.
|
||||||
*/
|
*/
|
||||||
Semaphore ad_sem;
|
Semaphore ad_sem;
|
||||||
/**
|
/**
|
||||||
* @brief Current callback function or @p NULL.
|
* @brief Current callback function or @p NULL.
|
||||||
*/
|
*/
|
||||||
adccallback_t ad_callback;
|
adccallback_t ad_callback;
|
||||||
|
/**
|
||||||
|
* @brief Current samples buffer pointer or @p NULL.
|
||||||
|
*/
|
||||||
|
adcsample_t *ad_samples;
|
||||||
|
/**
|
||||||
|
* @brief Current samples buffer depth or @p 0.
|
||||||
|
*/
|
||||||
|
size_t ad_depth;
|
||||||
|
/**
|
||||||
|
* @brief Current conversion group pointer or @p NULL.
|
||||||
|
*/
|
||||||
|
ADCConversionGroup *ad_grpp;
|
||||||
/* End of the mandatory fields.*/
|
/* End of the mandatory fields.*/
|
||||||
/**
|
/**
|
||||||
* @brief Pointer to the ADCx registers block.
|
* @brief Pointer to the ADCx registers block.
|
||||||
|
@ -190,20 +210,19 @@ typedef struct {
|
||||||
/* External declarations. */
|
/* External declarations. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/** @cond never*/
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
void adc_lld_init(void);
|
void adc_lld_init(void);
|
||||||
void adc_lld_start(ADCDriver *adcp);
|
void adc_lld_start(ADCDriver *adcp);
|
||||||
void adc_lld_stop(ADCDriver *adcp);
|
void adc_lld_stop(ADCDriver *adcp);
|
||||||
void adc_lld_start_conversion(ADCDriver *adcp,
|
void adc_lld_start_conversion(ADCDriver *adcp);
|
||||||
ADCConversionGroup *grpp,
|
|
||||||
void *samples,
|
|
||||||
size_t depth);
|
|
||||||
void adc_lld_stop_conversion(ADCDriver *adcp);
|
void adc_lld_stop_conversion(ADCDriver *adcp);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
/** @endcond*/
|
||||||
|
|
||||||
#endif /* _ADC_LLD_H_ */
|
#endif /* _ADC_LLD_H_ */
|
||||||
|
|
||||||
|
|
|
@ -34,11 +34,19 @@
|
||||||
SPIDriver SPID1;
|
SPIDriver SPID1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
#if USE_STM32_SPI2 || defined(__DOXYGEN__)
|
#if USE_STM32_SPI2 || defined(__DOXYGEN__)
|
||||||
/** @brief SPI2 driver identifier.*/
|
/** @brief SPI2 driver identifier.*/
|
||||||
SPIDriver SPID2;
|
SPIDriver SPID2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver local variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
static uint16_t dummyrx;
|
static uint16_t dummyrx;
|
||||||
static uint16_t dummytx;
|
static uint16_t dummytx;
|
||||||
|
|
||||||
|
@ -107,8 +115,9 @@ CH_IRQ_HANDLER(Vector70) {
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
spi_stop(&SPID1);
|
spi_stop(&SPID1);
|
||||||
if ((DMA1->ISR & DMA_ISR_TEIF2) != 0)
|
if ((DMA1->ISR & DMA_ISR_TEIF2) != 0) {
|
||||||
chEvtBroadcastI(&SPID1.spd_dmaerror);
|
STM32_SPI1_DMA_ERROR_HOOK();
|
||||||
|
}
|
||||||
DMA1->IFCR |= DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 |
|
DMA1->IFCR |= DMA_IFCR_CGIF2 | DMA_IFCR_CTCIF2 |
|
||||||
DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;
|
DMA_IFCR_CHTIF2 | DMA_IFCR_CTEIF2;
|
||||||
|
|
||||||
|
@ -122,7 +131,7 @@ CH_IRQ_HANDLER(Vector74) {
|
||||||
|
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
chEvtBroadcastI(&SPID1.spd_dmaerror);
|
STM32_SPI1_DMA_ERROR_HOOK();
|
||||||
DMA1->IFCR |= DMA_IFCR_CGIF3 | DMA_IFCR_CTCIF3 |
|
DMA1->IFCR |= DMA_IFCR_CGIF3 | DMA_IFCR_CTCIF3 |
|
||||||
DMA_IFCR_CHTIF3 | DMA_IFCR_CTEIF3;
|
DMA_IFCR_CHTIF3 | DMA_IFCR_CTEIF3;
|
||||||
|
|
||||||
|
@ -139,8 +148,9 @@ CH_IRQ_HANDLER(Vector78) {
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
spi_stop(&SPID2);
|
spi_stop(&SPID2);
|
||||||
if ((DMA1->ISR & DMA_ISR_TEIF4) != 0)
|
if ((DMA1->ISR & DMA_ISR_TEIF4) != 0) {
|
||||||
chEvtBroadcastI(&SPID2.spd_dmaerror);
|
STM32_SPI2_DMA_ERROR_HOOK();
|
||||||
|
}
|
||||||
DMA1->IFCR |= DMA_IFCR_CGIF4 | DMA_IFCR_CTCIF4 |
|
DMA1->IFCR |= DMA_IFCR_CGIF4 | DMA_IFCR_CTCIF4 |
|
||||||
DMA_IFCR_CHTIF4 | DMA_IFCR_CTEIF4;
|
DMA_IFCR_CHTIF4 | DMA_IFCR_CTEIF4;
|
||||||
|
|
||||||
|
@ -154,7 +164,7 @@ CH_IRQ_HANDLER(Vector7C) {
|
||||||
|
|
||||||
CH_IRQ_PROLOGUE();
|
CH_IRQ_PROLOGUE();
|
||||||
|
|
||||||
chEvtBroadcastI(&SPID2.spd_dmaerror);
|
STM32_SPI2_DMA_ERROR_HOOK();
|
||||||
DMA1->IFCR |= DMA_IFCR_CGIF5 | DMA_IFCR_CTCIF5 |
|
DMA1->IFCR |= DMA_IFCR_CGIF5 | DMA_IFCR_CTCIF5 |
|
||||||
DMA_IFCR_CHTIF5 | DMA_IFCR_CTEIF5;
|
DMA_IFCR_CHTIF5 | DMA_IFCR_CTEIF5;
|
||||||
|
|
||||||
|
@ -180,7 +190,6 @@ void spi_lld_init(void) {
|
||||||
SPID1.spd_dmarx = DMA1_Channel2;
|
SPID1.spd_dmarx = DMA1_Channel2;
|
||||||
SPID1.spd_dmatx = DMA1_Channel3;
|
SPID1.spd_dmatx = DMA1_Channel3;
|
||||||
SPID1.spd_dmaprio = STM32_SPI1_DMA_PRIORITY << 12;
|
SPID1.spd_dmaprio = STM32_SPI1_DMA_PRIORITY << 12;
|
||||||
chEvtInit(&SPID1.spd_dmaerror);
|
|
||||||
GPIOA->CRL = (GPIOA->CRL & 0x000FFFFF) | 0xB4B00000;
|
GPIOA->CRL = (GPIOA->CRL & 0x000FFFFF) | 0xB4B00000;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -191,7 +200,6 @@ void spi_lld_init(void) {
|
||||||
SPID2.spd_dmarx = DMA1_Channel4;
|
SPID2.spd_dmarx = DMA1_Channel4;
|
||||||
SPID2.spd_dmatx = DMA1_Channel5;
|
SPID2.spd_dmatx = DMA1_Channel5;
|
||||||
SPID2.spd_dmaprio = STM32_SPI2_DMA_PRIORITY << 12;
|
SPID2.spd_dmaprio = STM32_SPI2_DMA_PRIORITY << 12;
|
||||||
chEvtInit(&SPID2.spd_dmaerror);
|
|
||||||
GPIOB->CRH = (GPIOB->CRH & 0x000FFFFF) | 0xB4B00000;
|
GPIOB->CRH = (GPIOB->CRH & 0x000FFFFF) | 0xB4B00000;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -207,7 +215,7 @@ void spi_lld_start(SPIDriver *spip) {
|
||||||
if (spip->spd_state == SPI_STOP) {
|
if (spip->spd_state == SPI_STOP) {
|
||||||
#if USE_STM32_SPI1
|
#if USE_STM32_SPI1
|
||||||
if (&SPID1 == spip) {
|
if (&SPID1 == spip) {
|
||||||
dmaEnable(DMA1_ID);
|
dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
|
||||||
NVICEnableVector(DMA1_Channel2_IRQn, STM32_SPI1_IRQ_PRIORITY);
|
NVICEnableVector(DMA1_Channel2_IRQn, STM32_SPI1_IRQ_PRIORITY);
|
||||||
NVICEnableVector(DMA1_Channel3_IRQn, STM32_SPI1_IRQ_PRIORITY);
|
NVICEnableVector(DMA1_Channel3_IRQn, STM32_SPI1_IRQ_PRIORITY);
|
||||||
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
|
RCC->APB2ENR |= RCC_APB2ENR_SPI1EN;
|
||||||
|
@ -215,7 +223,7 @@ void spi_lld_start(SPIDriver *spip) {
|
||||||
#endif
|
#endif
|
||||||
#if USE_STM32_SPI2
|
#if USE_STM32_SPI2
|
||||||
if (&SPID2 == spip) {
|
if (&SPID2 == spip) {
|
||||||
dmaEnable(DMA1_ID);
|
dmaEnable(DMA1_ID); /* NOTE: Must be enabled before the IRQs.*/
|
||||||
NVICEnableVector(DMA1_Channel4_IRQn, STM32_SPI2_IRQ_PRIORITY);
|
NVICEnableVector(DMA1_Channel4_IRQn, STM32_SPI2_IRQ_PRIORITY);
|
||||||
NVICEnableVector(DMA1_Channel5_IRQn, STM32_SPI2_IRQ_PRIORITY);
|
NVICEnableVector(DMA1_Channel5_IRQn, STM32_SPI2_IRQ_PRIORITY);
|
||||||
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
|
RCC->APB1ENR |= RCC_APB1ENR_SPI2EN;
|
||||||
|
|
|
@ -93,6 +93,24 @@
|
||||||
#define STM32_SPI2_IRQ_PRIORITY 0x60
|
#define STM32_SPI2_IRQ_PRIORITY 0x60
|
||||||
#endif
|
#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.
|
||||||
|
*/
|
||||||
|
#if !defined(STM32_SPI1_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||||
|
#define STM32_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_SPI2_DMA_ERROR_HOOK) || defined(__DOXYGEN__)
|
||||||
|
#define STM32_SPI2_DMA_ERROR_HOOK() chSysHalt()
|
||||||
|
#endif
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Driver data structures and types. */
|
/* Driver data structures and types. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -158,10 +176,6 @@ typedef struct {
|
||||||
* @brief DMA priority bit mask.
|
* @brief DMA priority bit mask.
|
||||||
*/
|
*/
|
||||||
uint32_t spd_dmaprio;
|
uint32_t spd_dmaprio;
|
||||||
/**
|
|
||||||
* @brief DMA error event.
|
|
||||||
*/
|
|
||||||
EventSource spd_dmaerror;
|
|
||||||
} SPIDriver;
|
} SPIDriver;
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
|
@ -27,6 +27,14 @@
|
||||||
#include <ch.h>
|
#include <ch.h>
|
||||||
#include <adc.h>
|
#include <adc.h>
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver local variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Low Level Driver local functions. */
|
/* Low Level Driver local functions. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
@ -72,20 +80,8 @@ void adc_lld_stop(ADCDriver *adcp) {
|
||||||
* @brief Starts an ADC conversion.
|
* @brief Starts an ADC conversion.
|
||||||
*
|
*
|
||||||
* @param[in] adcp pointer to the @p ADCDriver object
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
* @param[in] grpp pointer to a @p ADCConversionGroup object
|
|
||||||
* @param[out] samples pointer to the samples buffer
|
|
||||||
* @param[in] depth buffer depth (matrix rows number). The buffer depth
|
|
||||||
* must be one or an even number.
|
|
||||||
*
|
|
||||||
* @note The buffer is organized as a matrix of M*N elements where M is the
|
|
||||||
* channels number configured into the conversion group and N is the
|
|
||||||
* buffer depth. The samples are sequentially written into the buffer
|
|
||||||
* with no gaps.
|
|
||||||
*/
|
*/
|
||||||
void adc_lld_start_conversion(ADCDriver *adcp,
|
void adc_lld_start_conversion(ADCDriver *adcp) {
|
||||||
ADCConversionGroup *grpp,
|
|
||||||
void *samples,
|
|
||||||
size_t depth) {
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ typedef struct {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Driver configuration structure.
|
* @brief Driver configuration structure.
|
||||||
|
* @note It could be empty on some architectures.
|
||||||
*/
|
*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
||||||
|
@ -88,13 +89,25 @@ typedef struct {
|
||||||
*/
|
*/
|
||||||
const ADCConfig *ad_config;
|
const ADCConfig *ad_config;
|
||||||
/**
|
/**
|
||||||
* @brief Semaphore for completion synchronization.
|
* @brief Synchronization semaphore.
|
||||||
*/
|
*/
|
||||||
Semaphore ac_sem;
|
Semaphore ad_sem;
|
||||||
/**
|
/**
|
||||||
* @brief Current callback function or @p NULL.
|
* @brief Current callback function or @p NULL.
|
||||||
*/
|
*/
|
||||||
adccallback_t ad_callback;
|
adccallback_t ad_callback;
|
||||||
|
/**
|
||||||
|
* @brief Current samples buffer pointer or @p NULL.
|
||||||
|
*/
|
||||||
|
adcsample_t *ad_samples;
|
||||||
|
/**
|
||||||
|
* @brief Current samples buffer depth or @p 0.
|
||||||
|
*/
|
||||||
|
size_t ad_depth;
|
||||||
|
/**
|
||||||
|
* @brief Current conversion group pointer or @p NULL.
|
||||||
|
*/
|
||||||
|
ADCConversionGroup *ad_grpp;
|
||||||
/* End of the mandatory fields.*/
|
/* End of the mandatory fields.*/
|
||||||
} ADCDriver;
|
} ADCDriver;
|
||||||
|
|
||||||
|
@ -108,10 +121,7 @@ extern "C" {
|
||||||
void adc_lld_init(void);
|
void adc_lld_init(void);
|
||||||
void adc_lld_start(ADCDriver *adcp);
|
void adc_lld_start(ADCDriver *adcp);
|
||||||
void adc_lld_stop(ADCDriver *adcp);
|
void adc_lld_stop(ADCDriver *adcp);
|
||||||
void adc_lld_start_conversion(ADCDriver *adcp,
|
void adc_lld_start_conversion(ADCDriver *adcp);
|
||||||
ADCConversionGroup *grpp,
|
|
||||||
void *samples,
|
|
||||||
size_t depth);
|
|
||||||
void adc_lld_stop_conversion(ADCDriver *adcp);
|
void adc_lld_stop_conversion(ADCDriver *adcp);
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,14 @@
|
||||||
#include <ch.h>
|
#include <ch.h>
|
||||||
#include <spi.h>
|
#include <spi.h>
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Low Level Driver local variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
/* Low Level Driver local functions. */
|
/* Low Level Driver local functions. */
|
||||||
/*===========================================================================*/
|
/*===========================================================================*/
|
||||||
|
|
|
@ -3,8 +3,13 @@
|
||||||
*****************************************************************************
|
*****************************************************************************
|
||||||
|
|
||||||
*** 1.3.5 ***
|
*** 1.3.5 ***
|
||||||
|
- NEW: STM32 ADC driver implementation with DMA support.
|
||||||
|
- CHANGE: In the STM32 drivers now the DMA errors are handled by hook macros
|
||||||
|
rather than by events. The default action is to halt the system but users
|
||||||
|
are able to override this and define custom handling.
|
||||||
- CHANGE: In the Cortex-M3 port, modified the NVICEnableVector() function
|
- CHANGE: In the Cortex-M3 port, modified the NVICEnableVector() function
|
||||||
to make it clear pending interrupts.
|
to make it clear pending interrupts.
|
||||||
|
- CHANGE: Minor changes to the ADC driver model.
|
||||||
|
|
||||||
*** 1.3.4 ***
|
*** 1.3.4 ***
|
||||||
- FIX: Fixed bug in STM32 PAL port driver (bug 2897636).
|
- FIX: Fixed bug in STM32 PAL port driver (bug 2897636).
|
||||||
|
|
Loading…
Reference in New Issue