mirror of
https://github.com/portapack-mayhem/mayhem-firmware.git
synced 2025-12-12 01:21:54 +00:00
ChibiOS 2.6.8, until I can figure out where to get it from git.
This commit is contained in:
744
firmware/chibios/os/hal/platforms/SPC5xx/EQADC_v1/adc_lld.c
Executable file
744
firmware/chibios/os/hal/platforms/SPC5xx/EQADC_v1/adc_lld.c
Executable file
@@ -0,0 +1,744 @@
|
||||
/*
|
||||
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SPC5xx/EQADC_v1/adc_lld.c
|
||||
* @brief SPC5xx low level ADC driver code.
|
||||
*
|
||||
* @addtogroup ADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#include "ch.h"
|
||||
#include "hal.h"
|
||||
|
||||
#if HAL_USE_ADC || defined(__DOXYGEN__)
|
||||
|
||||
/* Some forward declarations.*/
|
||||
static void adc_serve_rfifo_irq(edma_channel_t channel, void *p);
|
||||
static void adc_serve_dma_error_irq(edma_channel_t channel,
|
||||
void *p,
|
||||
uint32_t esr);
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Calibration constant.
|
||||
* @details Ideal conversion result for 75%(VRH - VRL) minus 2.
|
||||
*/
|
||||
#define ADC_IDEAL_RES75_2 12286
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported variables. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief ADCD1 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC0_Q0 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD1;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD2 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC0_Q1 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD2;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD3 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC0_Q2 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD3;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD4 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC1_Q3 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD4;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD5 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC1_Q4 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD5;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD6 driver identifier.
|
||||
*/
|
||||
#if SPC5_ADC_USE_ADC1_Q5 || defined(__DOXYGEN__)
|
||||
ADCDriver ADCD6;
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local variables and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Number of active ADC FIFOs.
|
||||
*/
|
||||
static uint32_t adc_active_fifos;
|
||||
|
||||
/**
|
||||
* @brief Static setup for input resistors.
|
||||
*/
|
||||
static const uint16_t pudcrs[8] = SPC5_ADC_PUDCR;
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q0 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO0.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo0_dma_config = {
|
||||
0, SPC5_ADC_FIFO0_DMA_PRIO, SPC5_ADC_FIFO0_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD1
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO0.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo0_dma_config = {
|
||||
1, SPC5_ADC_FIFO0_DMA_PRIO, SPC5_ADC_FIFO0_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD1
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q0 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q1 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO1.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo1_dma_config = {
|
||||
2, SPC5_ADC_FIFO1_DMA_PRIO, SPC5_ADC_FIFO1_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD2
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO1.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo1_dma_config = {
|
||||
3, SPC5_ADC_FIFO1_DMA_PRIO, SPC5_ADC_FIFO1_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD2
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q1 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q2 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO2.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo2_dma_config = {
|
||||
4, SPC5_ADC_FIFO2_DMA_PRIO, SPC5_ADC_FIFO2_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD3
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO2.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo2_dma_config = {
|
||||
5, SPC5_ADC_FIFO2_DMA_PRIO, SPC5_ADC_FIFO2_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD3
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q2 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q3 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO3.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo3_dma_config = {
|
||||
6, SPC5_ADC_FIFO3_DMA_PRIO, SPC5_ADC_FIFO3_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD4
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO3.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo3_dma_config = {
|
||||
7, SPC5_ADC_FIFO3_DMA_PRIO, SPC5_ADC_FIFO3_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD4
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q3 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q4 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO4.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo4_dma_config = {
|
||||
8, SPC5_ADC_FIFO4_DMA_PRIO, SPC5_ADC_FIFO4_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD5
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO4.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo4_dma_config = {
|
||||
9, SPC5_ADC_FIFO4_DMA_PRIO, SPC5_ADC_FIFO4_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD5
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q4 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q5 || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief DMA configuration for EQADC CFIFO5.
|
||||
*/
|
||||
static const edma_channel_config_t adc_cfifo5_dma_config = {
|
||||
10, SPC5_ADC_FIFO5_DMA_PRIO, SPC5_ADC_FIFO5_DMA_IRQ_PRIO,
|
||||
NULL, adc_serve_dma_error_irq, &ADCD6
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief DMA configuration for EQADC RFIFO5.
|
||||
*/
|
||||
static const edma_channel_config_t adc_rfifo5_dma_config = {
|
||||
11, SPC5_ADC_FIFO5_DMA_PRIO, SPC5_ADC_FIFO5_DMA_IRQ_PRIO,
|
||||
adc_serve_rfifo_irq, adc_serve_dma_error_irq, &ADCD6
|
||||
};
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q5 */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local functions and macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Unsigned two's complement.
|
||||
*
|
||||
* @param[in] n the value to be complemented
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define CPL2(n) ((~(uint32_t)(n)) + 1)
|
||||
|
||||
/**
|
||||
* @brief Address of a CFIFO push register.
|
||||
*
|
||||
* @param[in] fifo the FIFO identifier
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define CFIFO_PUSH_ADDR(fifo) ((uint32_t *)(&EQADC.CFPR[fifo].R))
|
||||
|
||||
/**
|
||||
* @brief Address of a RFIFO pop register.
|
||||
*
|
||||
* @param[in] fifo the FIFO identifier
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define RFIFO_POP_ADDR(fifo) (((uint16_t *)&EQADC.RFPR[fifo].R) + 1)
|
||||
|
||||
/**
|
||||
* @brief Enables a CFIFO.
|
||||
*
|
||||
* @param[in] fifo the FIFO identifier
|
||||
* @param[in] cfcr CFCR register value
|
||||
* @param[in] idcr IDCR register value
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void cfifo_enable(adcfifo_t fifo, uint16_t cfcr, uint16_t idcr) {
|
||||
|
||||
EQADC.CFCR[fifo].R = cfcr;
|
||||
EQADC.IDCR[fifo].R = idcr;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables a CFIFO and the associated resources.
|
||||
*
|
||||
* @param[in] fifo the FIFO identifier
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void cfifo_disable(adcfifo_t fifo) {
|
||||
|
||||
/* Disables the CFIFO.*/
|
||||
EQADC.CFCR[fifo].R = EQADC_CFCR_MODE_DISABLED;
|
||||
|
||||
/* Disables Interrupts and DMAs of the CFIFO.*/
|
||||
EQADC.IDCR[fifo].R = 0;
|
||||
|
||||
/* Waits for the CFIFO to become idle.*/
|
||||
while ((EQADC.CFSR.R & (0xC0000000 >> (fifo * 2))) != 0)
|
||||
;
|
||||
|
||||
/* Invalidates the CFIFO.*/
|
||||
EQADC.CFCR[fifo].R = EQADC_CFCR_CFINV | EQADC_CFCR_MODE_DISABLED;
|
||||
|
||||
/* Clears all Interrupts and eDMA flags for the CFIFO.*/
|
||||
EQADC.FISR[fifo].R = EQADC_FISR_CLEAR_MASK;
|
||||
|
||||
/* Clears the Tx Count Registers for the CFIFO.*/
|
||||
EQADC.CFTCR[fifo].R = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Pushes a command into the CFIFO0.
|
||||
*
|
||||
* @param[in] cmd the command
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void cfifo0_push_command(adccommand_t cmd) {
|
||||
|
||||
while (EQADC.FISR[0].B.CFCTR >= 4)
|
||||
;
|
||||
EQADC.CFPR[0].R = cmd;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Waits until the RFIFO0 contains the specified number of entries.
|
||||
*
|
||||
* @param[in] n number of entries
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void cfifo0_wait_rfifo(uint32_t n) {
|
||||
|
||||
while (EQADC.FISR[0].B.RFCTR < n)
|
||||
;
|
||||
EQADC.FISR[0].R = EQADC_FISR_CLEAR_MASK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Reads a sample from the RFIFO0.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define rfifo0_get_value() (EQADC.RFPR[0].R)
|
||||
|
||||
/**
|
||||
* @brief Writes an internal ADC register.
|
||||
*
|
||||
* @param[in] adc the ADC unit
|
||||
* @param[in] reg the register index
|
||||
* @param[in] value value to be written into the register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
#define adc_write_register(adc, reg, value) \
|
||||
cfifo0_push_command(EQADC_RW_WRITE | (adc) | EQADC_RW_REG_ADDR(reg) | \
|
||||
EQADC_RW_VALUE(value))
|
||||
|
||||
|
||||
/**
|
||||
* @brief Enables both ADCs.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_enable(void) {
|
||||
|
||||
/* Both ADCs must be enabled because this sentence in the reference manual:
|
||||
"Both ADC0 and ADC1 of an eQADC module pair must be enabled before
|
||||
calibrating or using either ADC0 or ADC1 of the pair. Failure to
|
||||
enable both ADC0 and ADC1 of the pair can result in inaccurate
|
||||
conversions.".*/
|
||||
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_CR,
|
||||
SPC5_ADC_CR_CLK_PS | ADC_CR_EN);
|
||||
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_CR,
|
||||
SPC5_ADC_CR_CLK_PS | ADC_CR_EN);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Disables both ADCs.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_disable(void) {
|
||||
|
||||
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_CR,
|
||||
SPC5_ADC_CR_CLK_PS);
|
||||
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_CR,
|
||||
SPC5_ADC_CR_CLK_PS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calibrates an ADC unit.
|
||||
*
|
||||
* @param[in] adc the ADC unit
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_calibrate(uint32_t adc) {
|
||||
uint16_t res25, res75;
|
||||
uint32_t gcc, occ;
|
||||
|
||||
/* Starts the calibration, write command messages to sample 25% and
|
||||
75% VREF.*/
|
||||
cfifo0_push_command(0x00002C00 | adc); /* Vref 25%.*/
|
||||
cfifo0_push_command(0x00002B00 | adc); /* Vref 75%.*/
|
||||
cfifo0_wait_rfifo(2);
|
||||
|
||||
/* Reads the results and compute calibration register values.*/
|
||||
res25 = rfifo0_get_value();
|
||||
res75 = rfifo0_get_value();
|
||||
|
||||
gcc = 0x08000000UL / ((uint32_t)res75 - (uint32_t)res25);
|
||||
occ = (uint32_t)ADC_IDEAL_RES75_2 - ((gcc * (uint32_t)res75) >> 14);
|
||||
|
||||
/* Loads the gain and offset values (default configuration, 12 bits).*/
|
||||
adc_write_register(adc, ADC_REG_GCCR, gcc);
|
||||
adc_write_register(adc, ADC_REG_OCCR, occ & 0xFFFF);
|
||||
|
||||
/* Loads gain and offset values (alternate configuration 1, 10 bits).*/
|
||||
adc_write_register(adc, ADC_REG_AC1GCCR, gcc);
|
||||
adc_write_register(adc, ADC_REG_AC1OCCR, occ & 0xFFFF);
|
||||
|
||||
/* Loads gain and offset values (alternate configuration 1, 8 bits).*/
|
||||
adc_write_register(adc, ADC_REG_AC2GCCR, gcc);
|
||||
adc_write_register(adc, ADC_REG_AC2OCCR, occ & 0xFFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Calibrates an ADC unit.
|
||||
*
|
||||
* @param[in] adc the ADC unit
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_setup_resistors(uint32_t adc) {
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i < 8; i++)
|
||||
adc_write_register(adc, ADC_REG_PUDCR(i), pudcrs[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shared ISR for RFIFO DMA events.
|
||||
*
|
||||
* @param[in] channel the channel number
|
||||
* @param[in] p parameter for the registered function
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_serve_rfifo_irq(edma_channel_t channel, void *p) {
|
||||
ADCDriver *adcp = (ADCDriver *)p;
|
||||
edma_tcd_t *tcdp = edmaGetTCD(channel);
|
||||
|
||||
if (adcp->grpp != NULL) {
|
||||
if ((tcdp->word[5] >> 16) != (tcdp->word[7] >> 16)) {
|
||||
/* Half transfer processing.*/
|
||||
_adc_isr_half_code(adcp);
|
||||
}
|
||||
else {
|
||||
/* Re-starting DMA channels if in circular mode.*/
|
||||
if (adcp->grpp->circular) {
|
||||
edmaChannelStart(adcp->rfifo_channel);
|
||||
edmaChannelStart(adcp->cfifo_channel);
|
||||
}
|
||||
|
||||
/* Transfer complete processing.*/
|
||||
_adc_isr_full_code(adcp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shared ISR for CFIFO/RFIFO DMA error events.
|
||||
*
|
||||
* @param[in] channel the channel number
|
||||
* @param[in] p parameter for the registered function
|
||||
* @param[in] esr content of the ESR register
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static void adc_serve_dma_error_irq(edma_channel_t channel,
|
||||
void *p,
|
||||
uint32_t esr) {
|
||||
ADCDriver *adcp = (ADCDriver *)p;
|
||||
|
||||
(void)channel;
|
||||
(void)esr;
|
||||
|
||||
_adc_isr_error_code(adcp, ADC_ERR_DMAFAILURE);
|
||||
}
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver interrupt handlers. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver exported functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Low level ADC driver initialization.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_init(void) {
|
||||
|
||||
/* FIFOs initially all not in use.*/
|
||||
adc_active_fifos = 0;
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q0
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD1);
|
||||
ADCD1.cfifo_channel = EDMA_ERROR;
|
||||
ADCD1.rfifo_channel = EDMA_ERROR;
|
||||
ADCD1.fifo = ADC_FIFO_0;
|
||||
#endif /* SPC5_ADC_USE_EQADC_Q0 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q1
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD2);
|
||||
ADCD2.cfifo_channel = EDMA_ERROR;
|
||||
ADCD2.rfifo_channel = EDMA_ERROR;
|
||||
ADCD2.fifo = ADC_FIFO_1;
|
||||
#endif /* SPC5_ADC_USE_EQADC_Q1 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q2
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD3);
|
||||
ADCD3.cfifo_channel = EDMA_ERROR;
|
||||
ADCD3.rfifo_channel = EDMA_ERROR;
|
||||
ADCD3.fifo = ADC_FIFO_2;
|
||||
#endif /* SPC5_ADC_USE_EQADC_Q2 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q3
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD4);
|
||||
ADCD4.cfifo_channel = EDMA_ERROR;
|
||||
ADCD4.rfifo_channel = EDMA_ERROR;
|
||||
ADCD4.fifo = ADC_FIFO_3;
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q3 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q4
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD5);
|
||||
ADCD5.cfifo_channel = EDMA_ERROR;
|
||||
ADCD5.rfifo_channel = EDMA_ERROR;
|
||||
ADCD5.fifo = ADC_FIFO_4;
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q4 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q5
|
||||
/* Driver initialization.*/
|
||||
adcObjectInit(&ADCD6);
|
||||
ADCD6.cfifo_channel = EDMA_ERROR;
|
||||
ADCD6.rfifo_channel = EDMA_ERROR;
|
||||
ADCD6.fifo = ADC_FIFO_5;
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q5 */
|
||||
|
||||
/* Temporarily enables CFIFO0 for calibration and initialization.*/
|
||||
cfifo_enable(ADC_FIFO_0, EQADC_CFCR_SSE | EQADC_CFCR_MODE_SWCS, 0);
|
||||
adc_enable();
|
||||
|
||||
/* Calibration of both ADC units, programming alternate configs
|
||||
one and two for 10 and 8 bits operations, setting up pull up/down
|
||||
resistors.*/
|
||||
#if SPC5_ADC_USE_ADC0
|
||||
adc_calibrate(EQADC_RW_BN_ADC0);
|
||||
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_AC1CR, ADC_ACR_RESSEL_10BITS);
|
||||
adc_write_register(EQADC_RW_BN_ADC0, ADC_REG_AC2CR, ADC_ACR_RESSEL_8BITS);
|
||||
adc_setup_resistors(EQADC_RW_BN_ADC0);
|
||||
#endif
|
||||
#if SPC5_ADC_USE_ADC1
|
||||
adc_calibrate(EQADC_RW_BN_ADC1);
|
||||
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_AC1CR, ADC_ACR_RESSEL_10BITS);
|
||||
adc_write_register(EQADC_RW_BN_ADC1, ADC_REG_AC2CR, ADC_ACR_RESSEL_8BITS);
|
||||
adc_setup_resistors(EQADC_RW_BN_ADC1);
|
||||
#endif
|
||||
|
||||
/* ADCs disabled until the driver is started by the application.*/
|
||||
adc_disable();
|
||||
cfifo_disable(ADC_FIFO_0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Configures and activates the ADC peripheral.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_start(ADCDriver *adcp) {
|
||||
|
||||
chDbgAssert(adc_active_fifos < 6, "adc_lld_start(), #1", "too many FIFOs");
|
||||
|
||||
if (adcp->state == ADC_STOP) {
|
||||
/* Enables the peripheral.*/
|
||||
#if SPC5_ADC_USE_ADC0_Q0
|
||||
if (&ADCD1 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo0_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo0_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q0 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q1
|
||||
if (&ADCD2 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo1_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo1_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q1 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q2
|
||||
if (&ADCD3 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo2_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo2_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC0_Q2 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q3
|
||||
if (&ADCD4 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo3_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo3_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q3 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q4
|
||||
if (&ADCD5 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo4_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo4_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q4 */
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q5
|
||||
if (&ADCD6 == adcp) {
|
||||
adcp->cfifo_channel = edmaChannelAllocate(&adc_cfifo5_dma_config);
|
||||
adcp->rfifo_channel = edmaChannelAllocate(&adc_rfifo5_dma_config);
|
||||
adc_active_fifos++;
|
||||
}
|
||||
#endif /* SPC5_ADC_USE_ADC1_Q5 */
|
||||
|
||||
/* If this is the first FIFO activated then the ADC is enabled.*/
|
||||
if (adc_active_fifos == 1)
|
||||
adc_enable();
|
||||
}
|
||||
|
||||
chDbgAssert((adcp->cfifo_channel != EDMA_ERROR) &&
|
||||
(adcp->rfifo_channel != EDMA_ERROR),
|
||||
"adc_lld_start(), #2", "channel cannot be allocated");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Deactivates the ADC peripheral.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_stop(ADCDriver *adcp) {
|
||||
|
||||
chDbgAssert(adc_active_fifos < 6, "adc_lld_stop(), #1", "too many FIFOs");
|
||||
|
||||
if (adcp->state == ADC_READY) {
|
||||
/* Resets the peripheral.*/
|
||||
|
||||
/* Releases the allocated EDMA channels.*/
|
||||
edmaChannelRelease(adcp->cfifo_channel);
|
||||
edmaChannelRelease(adcp->rfifo_channel);
|
||||
|
||||
/* If it is the last active FIFO then the ADC is disable too.*/
|
||||
if (--adc_active_fifos == 0)
|
||||
adc_disable();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Starts an ADC conversion.
|
||||
* @note Because an HW constraint the number of rows in the samples
|
||||
* array must not be greater than the preconfigured value in
|
||||
* the conversion group.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_start_conversion(ADCDriver *adcp) {
|
||||
uint32_t bitoff;
|
||||
|
||||
chDbgAssert(adcp->grpp->num_iterations >= adcp->depth,
|
||||
"adc_lld_start_conversion(), #1", "too many elements");
|
||||
|
||||
/* Setting up CFIFO TCD parameters.*/
|
||||
edmaChannelSetup(adcp->cfifo_channel, /* channel. */
|
||||
adcp->grpp->commands, /* src. */
|
||||
CFIFO_PUSH_ADDR(adcp->fifo), /* dst. */
|
||||
4, /* soff, advance by 4. */
|
||||
0, /* doff, do not advance. */
|
||||
2, /* ssize, 32 bits transfers.*/
|
||||
2, /* dsize, 32 bits transfers.*/
|
||||
4, /* nbytes, always four. */
|
||||
(uint32_t)adcp->grpp->num_channels *
|
||||
(uint32_t)adcp->depth, /* iter. */
|
||||
CPL2((uint32_t)adcp->grpp->num_channels *
|
||||
(uint32_t)adcp->depth *
|
||||
sizeof(adccommand_t)), /* slast. */
|
||||
0, /* dlast, no dest.adjust. */
|
||||
EDMA_TCD_MODE_DREQ); /* mode. */
|
||||
|
||||
/* Setting up RFIFO TCD parameters.*/
|
||||
edmaChannelSetup(adcp->rfifo_channel, /* channel. */
|
||||
RFIFO_POP_ADDR(adcp->fifo), /* src. */
|
||||
adcp->samples, /* dst. */
|
||||
0, /* soff, do not advance. */
|
||||
2, /* doff, advance by two. */
|
||||
1, /* ssize, 16 bits transfers.*/
|
||||
1, /* dsize, 16 bits transfers.*/
|
||||
2, /* nbytes, always two. */
|
||||
(uint32_t)adcp->grpp->num_channels *
|
||||
(uint32_t)adcp->depth, /* iter. */
|
||||
0, /* slast, no source adjust. */
|
||||
CPL2((uint32_t)adcp->grpp->num_channels *
|
||||
(uint32_t)adcp->depth *
|
||||
sizeof(adcsample_t)), /* dlast. */
|
||||
EDMA_TCD_MODE_DREQ | EDMA_TCD_MODE_INT_END |
|
||||
((adcp->depth > 1) ? EDMA_TCD_MODE_INT_HALF: 0));/* mode.*/
|
||||
|
||||
/* HW triggers setup.*/
|
||||
bitoff = 20 + ((uint32_t)adcp->fifo * 2);
|
||||
SIU.ETISR.R = (SIU.ETISR.R & ~(3U << bitoff)) |
|
||||
(adcp->grpp->tsel << bitoff);
|
||||
bitoff = (uint32_t)adcp->fifo * 5;
|
||||
SIU.ISEL3.R = (SIU.ISEL3.R & ~(31U << bitoff)) |
|
||||
(adcp->grpp->etsel << bitoff);
|
||||
|
||||
/* Starting DMA channels.*/
|
||||
edmaChannelStart(adcp->rfifo_channel);
|
||||
edmaChannelStart(adcp->cfifo_channel);
|
||||
|
||||
/* Enabling CFIFO, conversion starts.*/
|
||||
cfifo_enable(adcp->fifo, adcp->grpp->cfcr,
|
||||
EQADC_IDCR_CFFE | EQADC_IDCR_CFFS |
|
||||
EQADC_IDCR_RFDE | EQADC_IDCR_RFDS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Stops an ongoing conversion.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void adc_lld_stop_conversion(ADCDriver *adcp) {
|
||||
|
||||
/* Stopping DMA channels.*/
|
||||
edmaChannelStop(adcp->cfifo_channel);
|
||||
edmaChannelStop(adcp->rfifo_channel);
|
||||
|
||||
/* Disabling CFIFO.*/
|
||||
cfifo_disable(adcp->fifo);
|
||||
}
|
||||
|
||||
#endif /* HAL_USE_ADC */
|
||||
|
||||
/** @} */
|
||||
705
firmware/chibios/os/hal/platforms/SPC5xx/EQADC_v1/adc_lld.h
Executable file
705
firmware/chibios/os/hal/platforms/SPC5xx/EQADC_v1/adc_lld.h
Executable file
@@ -0,0 +1,705 @@
|
||||
/*
|
||||
SPC5 HAL - Copyright (C) 2013 STMicroelectronics
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file SPC5xx/EQADC_v1/adc_lld.c
|
||||
* @brief SPC5xx low level ADC driver header.
|
||||
*
|
||||
* @addtogroup ADC
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef _ADC_LLD_H_
|
||||
#define _ADC_LLD_H_
|
||||
|
||||
#if HAL_USE_ADC || defined(__DOXYGEN__)
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver constants. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Analog channel identifiers
|
||||
* @{
|
||||
*/
|
||||
#define ADC_CHN_AN0 0U
|
||||
#define ADC_CHN_AN1 1U
|
||||
#define ADC_CHN_AN2 2U
|
||||
#define ADC_CHN_AN3 3U
|
||||
#define ADC_CHN_AN4 4U
|
||||
#define ADC_CHN_AN5 5U
|
||||
#define ADC_CHN_AN6 6U
|
||||
#define ADC_CHN_AN7 7U
|
||||
#define ADC_CHN_AN8 8U
|
||||
#define ADC_CHN_AN9 9U
|
||||
#define ADC_CHN_AN10 10U
|
||||
#define ADC_CHN_AN11 11U
|
||||
#define ADC_CHN_AN12 12U
|
||||
#define ADC_CHN_AN13 13U
|
||||
#define ADC_CHN_AN14 14U
|
||||
#define ADC_CHN_AN15 15U
|
||||
#define ADC_CHN_AN16 16U
|
||||
#define ADC_CHN_AN17 17U
|
||||
#define ADC_CHN_AN18 18U
|
||||
#define ADC_CHN_AN19 19U
|
||||
#define ADC_CHN_AN20 20U
|
||||
#define ADC_CHN_AN21 21U
|
||||
#define ADC_CHN_AN22 22U
|
||||
#define ADC_CHN_AN23 23U
|
||||
#define ADC_CHN_AN24 24U
|
||||
#define ADC_CHN_AN25 25U
|
||||
#define ADC_CHN_AN26 26U
|
||||
#define ADC_CHN_AN27 27U
|
||||
#define ADC_CHN_AN28 28U
|
||||
#define ADC_CHN_AN29 29U
|
||||
#define ADC_CHN_AN30 30U
|
||||
#define ADC_CHN_AN31 31U
|
||||
#define ADC_CHN_AN32 32U
|
||||
#define ADC_CHN_AN33 33U
|
||||
#define ADC_CHN_AN34 34U
|
||||
#define ADC_CHN_AN35 35U
|
||||
#define ADC_CHN_AN36 36U
|
||||
#define ADC_CHN_AN37 37U
|
||||
#define ADC_CHN_AN38 38U
|
||||
#define ADC_CHN_AN39 39U
|
||||
#define ADC_CHN_VRH 40U
|
||||
#define ADC_CHN_VRL 41U
|
||||
#define ADC_CHN_VREF50 42U
|
||||
#define ADC_CHN_VREF75 43U
|
||||
#define ADC_CHN_VREF25 44U
|
||||
#define ADC_CHN_BANDGAP 45U
|
||||
#define ADC_CHN_DAN0 96U
|
||||
#define ADC_CHN_DAN1 97U
|
||||
#define ADC_CHN_DAN2 98U
|
||||
#define ADC_CHN_DAN3 99U
|
||||
#define ADC_CHN_TEMP_SENSOR 128U
|
||||
#define ADC_CHN_SPARE 129U
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Internal registers indexes
|
||||
* @{
|
||||
*/
|
||||
#define ADC_REG_CR 0x1
|
||||
#define ADC_REG_TSCR 0x2
|
||||
#define ADC_REG_TBCR 0x3
|
||||
#define ADC_REG_GCCR 0x4
|
||||
#define ADC_REG_OCCR 0x5
|
||||
#define ADC_REG_AC1GCCR 0x31
|
||||
#define ADC_REG_AC1OCCR 0x32
|
||||
#define ADC_REG_AC2GCCR 0x35
|
||||
#define ADC_REG_AC2OCCR 0x36
|
||||
#define ADC_REG_AC1CR 0x30
|
||||
#define ADC_REG_AC2CR 0x34
|
||||
#define ADC_REG_AC3CR 0x38
|
||||
#define ADC_REG_AC4CR 0x3C
|
||||
#define ADC_REG_AC5CR 0x40
|
||||
#define ADC_REG_AC6CR 0x44
|
||||
#define ADC_REG_AC7CR 0x48
|
||||
#define ADC_REG_AC8CR 0x4C
|
||||
#define ADC_REG_PUDCR(n) (0x70 + (n))
|
||||
#define ADC_REG_PUDCR0 0x70UL
|
||||
#define ADC_REG_PUDCR1 0x71UL
|
||||
#define ADC_REG_PUDCR2 0x72UL
|
||||
#define ADC_REG_PUDCR3 0x73UL
|
||||
#define ADC_REG_PUDCR4 0x74UL
|
||||
#define ADC_REG_PUDCR5 0x75UL
|
||||
#define ADC_REG_PUDCR6 0x76UL
|
||||
#define ADC_REG_PUDCR7 0x77UL
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EQADC IDCR registers definitions
|
||||
* @{
|
||||
*/
|
||||
#define EQADC_IDCR_NCIE (1U << 15)
|
||||
#define EQADC_IDCR_TORIE (1U << 14)
|
||||
#define EQADC_IDCR_PIE (1U << 13)
|
||||
#define EQADC_IDCR_EOQIE (1U << 12)
|
||||
#define EQADC_IDCR_CFUIE (1U << 11)
|
||||
#define EQADC_IDCR_CFFE (1U << 9)
|
||||
#define EQADC_IDCR_CFFS (1U << 8)
|
||||
#define EQADC_IDCR_RFOIE (1U << 3)
|
||||
#define EQADC_IDCR_RFDE (1U << 1)
|
||||
#define EQADC_IDCR_RFDS (1U << 0)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EQADC CFCR registers definitions
|
||||
* @{
|
||||
*/
|
||||
#define EQADC_CFCR_CFEEE0 (1U << 12)
|
||||
#define EQADC_CFCR_STRME0 (1U << 11)
|
||||
#define EQADC_CFCR_SSE (1U << 10)
|
||||
#define EQADC_CFCR_CFINV (1U << 9)
|
||||
#define EQADC_CFCR_MODE_MASK (15U << 4)
|
||||
#define EQADC_CFCR_MODE(n) ((n) << 4)
|
||||
#define EQADC_CFCR_MODE_DISABLED EQADC_CFCR_MODE(0)
|
||||
#define EQADC_CFCR_MODE_SWSS EQADC_CFCR_MODE(1)
|
||||
#define EQADC_CFCR_MODE_HWSS_LL EQADC_CFCR_MODE(2)
|
||||
#define EQADC_CFCR_MODE_HWSS_HL EQADC_CFCR_MODE(3)
|
||||
#define EQADC_CFCR_MODE_HWSS_FE EQADC_CFCR_MODE(4)
|
||||
#define EQADC_CFCR_MODE_HWSS_RE EQADC_CFCR_MODE(5)
|
||||
#define EQADC_CFCR_MODE_HWSS_BE EQADC_CFCR_MODE(6)
|
||||
#define EQADC_CFCR_MODE_SWCS EQADC_CFCR_MODE(9)
|
||||
#define EQADC_CFCR_MODE_HWCS_LL EQADC_CFCR_MODE(10)
|
||||
#define EQADC_CFCR_MODE_HWCS_HL EQADC_CFCR_MODE(11)
|
||||
#define EQADC_CFCR_MODE_HWCS_FE EQADC_CFCR_MODE(12)
|
||||
#define EQADC_CFCR_MODE_HWCS_RE EQADC_CFCR_MODE(13)
|
||||
#define EQADC_CFCR_MODE_HWCS_BE EQADC_CFCR_MODE(14)
|
||||
#define EQADC_CFCR_AMODE0_MASK (15U << 0)
|
||||
#define EQADC_CFCR_AMODE0(n) ((n) << 0)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EQADC FISR registers definitions
|
||||
* @{
|
||||
*/
|
||||
#define EQADC_FISR_POPNXTPTR_MASK (15U << 0)
|
||||
#define EQADC_FISR_RFCTR_MASK (15U << 4)
|
||||
#define EQADC_FISR_TNXTPTR_MASK (15U << 8)
|
||||
#define EQADC_FISR_CFCTR_MASK (15U << 12)
|
||||
#define EQADC_FISR_RFDF (1U << 17)
|
||||
#define EQADC_FISR_RFOF (1U << 19)
|
||||
#define EQADC_FISR_CFFF (1U << 25)
|
||||
#define EQADC_FISR_SSS (1U << 26)
|
||||
#define EQADC_FISR_CFUF (1U << 27)
|
||||
#define EQADC_FISR_EOQF (1U << 28)
|
||||
#define EQADC_FISR_PF (1U << 29)
|
||||
#define EQADC_FISR_TORF (1U << 30)
|
||||
#define EQADC_FISR_NCF (1U << 31)
|
||||
#define EQADC_FISR_CLEAR_MASK (EQADC_FISR_NCF | EQADC_FISR_TORF | \
|
||||
EQADC_FISR_PF | EQADC_FISR_EOQF | \
|
||||
EQADC_FISR_CFUF | EQADC_FISR_RFOF | \
|
||||
EQADC_FISR_RFDF)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EQADC conversion/configuration commands
|
||||
* @{
|
||||
*/
|
||||
#define EQADC_CONV_CONFIG_STD (0U << 0) /**< @brief Alt.config.1. */
|
||||
#define EQADC_CONV_CONFIG_SEL1 (8U << 0) /**< @brief Alt.config.1. */
|
||||
#define EQADC_CONV_CONFIG_SEL2 (9U << 0) /**< @brief Alt.config.2. */
|
||||
#define EQADC_CONV_CONFIG_SEL3 (10U << 0) /**< @brief Alt.config.3. */
|
||||
#define EQADC_CONV_CONFIG_SEL4 (11U << 0) /**< @brief Alt.config.4. */
|
||||
#define EQADC_CONV_CONFIG_SEL5 (12U << 0) /**< @brief Alt.config.5. */
|
||||
#define EQADC_CONV_CONFIG_SEL6 (13U << 0) /**< @brief Alt.config.6. */
|
||||
#define EQADC_CONV_CONFIG_SEL7 (14U << 0) /**< @brief Alt.config.7. */
|
||||
#define EQADC_CONV_CONFIG_SEL8 (15U << 0) /**< @brief Alt.config.8. */
|
||||
#define EQADC_CONV_CHANNEL_MASK (255U << 8) /**< @brief Channel number mask.*/
|
||||
#define EQADC_CONV_CHANNEL(n) ((n) << 8) /**< @brief Channel number. */
|
||||
#define EQADC_CONV_FMT_RJU (0U << 16) /**< @brief Unsigned samples. */
|
||||
#define EQADC_CONV_FMT_RJS (1U << 16) /**< @brief Signed samples. */
|
||||
#define EQADC_CONV_TSR (1U << 17) /**< @brief Time stamp request. */
|
||||
#define EQADC_CONV_LST_MASK (3U << 18) /**< @brief Sample time. */
|
||||
#define EQADC_CONV_LST_2 (0U << 18) /**< @brief 2 clock cycles. */
|
||||
#define EQADC_CONV_LST_8 (1U << 18) /**< @brief 8 clock cycles. */
|
||||
#define EQADC_CONV_LST_64 (2U << 18) /**< @brief 64 clock cycles. */
|
||||
#define EQADC_CONV_LST_128 (3U << 18) /**< @brief 128 clock cycles. */
|
||||
#define EQADC_CONV_MSG_MASK (15U << 20) /**< @brief Message mask. */
|
||||
#define EQADC_CONV_MSG_RFIFO(n) ((n) << 20) /**< @brief Result in RFIFO0..5.*/
|
||||
#define EQADC_CONV_MSG_NULL (6U << 20) /**< @brief Null message. */
|
||||
#define EQADC_CONV_CAL (1U << 24) /**< @brief Calibrated result. */
|
||||
#define EQADC_CONV_BN_MASK (1U << 25) /**< @brief Buffer number mask. */
|
||||
#define EQADC_CONV_BN_ADC0 (0U << 25) /**< @brief ADC0 selection. */
|
||||
#define EQADC_CONV_BN_ADC1 (1U << 25) /**< @brief ADC1 selection. */
|
||||
#define EQADC_CONV_REP (1U << 29) /**< @brief Repeat loop flag. */
|
||||
#define EQADC_CONV_PAUSE (1U << 30) /**< @brief Pause flag. */
|
||||
#define EQADC_CONV_EOQ (1U << 31) /**< @brief End of queue flag. */
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name EQADC read/write commands
|
||||
* @{
|
||||
*/
|
||||
#define EQADC_RW_REG_ADDR_MASK (255U << 0)
|
||||
#define EQADC_RW_REG_ADDR(n) ((n) << 0)
|
||||
#define EQADC_RW_VALUE_MASK (0xFFFF << 8)
|
||||
#define EQADC_RW_VALUE(n) ((n) << 8)
|
||||
#define EQADC_RW_WRITE (0U << 24)
|
||||
#define EQADC_RW_READ (1U << 24)
|
||||
#define EQADC_RW_BN_ADC0 (0U << 25)
|
||||
#define EQADC_RW_BN_ADC1 (1U << 25)
|
||||
#define EQADC_RW_REP (1U << 29)
|
||||
#define EQADC_RW_PAUSE (1U << 30)
|
||||
#define EQADC_RW_EOQ (1U << 31)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name ADC CR register definitions
|
||||
* @{
|
||||
*/
|
||||
#define ADC_CR_CLK_PS_MASK (31U << 0)
|
||||
#define ADC_CR_CLK_PS(n) ((((n) >> 1) - 1) | ((n) & 1 ? ADC_CR_ODD_PS\
|
||||
: 0))
|
||||
#define ADC_CR_CLK_SEL (1U << 5)
|
||||
#define ADC_CR_CLK_DTY (1U << 6)
|
||||
#define ADC_CR_ODD_PS (1U << 7)
|
||||
#define ADC_CR_TBSEL_MASK (3U << 8)
|
||||
#define ADC_CR_TBSEL(n) ((n) << 8)
|
||||
#define ADC_CR_EMUX (1U << 11)
|
||||
#define ADC_CR_EN (1U << 15)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name ADC AxCR registers definitions
|
||||
* @{
|
||||
*/
|
||||
#define ADC_ACR_PRE_GAIN_MASK (3U << 0)
|
||||
#define ADC_ACR_PRE_GAIN_X1 (0U << 0)
|
||||
#define ADC_ACR_PRE_GAIN_X2 (1U << 0)
|
||||
#define ADC_ACR_PRE_GAIN_X4 (2U << 0)
|
||||
#define ADC_ACR_RESSEL_MASK (3U << 6)
|
||||
#define ADC_ACR_RESSEL_12BITS (0U << 6)
|
||||
#define ADC_ACR_RESSEL_10BITS (1U << 6)
|
||||
#define ADC_ACR_RESSEL_8BITS (2U << 6)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name ADC PUDCRx registers definitions
|
||||
* @{
|
||||
*/
|
||||
#define ADC_PUDCR_NONE 0x0000
|
||||
#define ADC_PUDCR_UP_200K 0x1100
|
||||
#define ADC_PUDCR_UP_100K 0x1200
|
||||
#define ADC_PUDCR_UP_5K 0x1300
|
||||
#define ADC_PUDCR_DOWN_200K 0x2100
|
||||
#define ADC_PUDCR_DOWN_100K 0x2200
|
||||
#define ADC_PUDCR_DOWN_5K 0x2300
|
||||
#define ADC_PUDCR_UP_DOWN_200K 0x3100
|
||||
#define ADC_PUDCR_UP_DOWN_100K 0x3200
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver pre-compile time settings. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @name Configuration options
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief ADCD1 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC0 queue 0 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC0_Q0) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC0_Q0 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD2 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC0 queue 1 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC0_Q1) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC0_Q1 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD3 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC0 queue 2 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC0_Q2) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC0_Q2 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD4 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC1 queue 3 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC1_Q3) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC1_Q3 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD5 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC1 queue 4 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC1_Q4) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC1_Q4 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief ADCD6 driver enable switch.
|
||||
* @details If set to @p TRUE the support for ADC1 queue 5 is included.
|
||||
* @note The default is @p FALSE.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_USE_ADC1_Q5) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_USE_ADC1_Q5 FALSE
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO0 and RFIFO0 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO0_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO0_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO1 and RFIFO1 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO1_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO1_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO2 and RFIFO2 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO2_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO2_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO3 and RFIFO3 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO3_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO3_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO4 and RFIFO4 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO4_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO4_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO5 and RFIFO5 DMA priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_FIFO5_DMA_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO5_DMA_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO0 and RFIFO0 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO0_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO0_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO1 and RFIFO1 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO1_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO1_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO2 and RFIFO2 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO2_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO2_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO3 and RFIFO3 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO3_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO3_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO4 and RFIFO4 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO4_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO4_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC CFIFO5 and RFIFO5 DMA IRQ priority.
|
||||
*/
|
||||
#if !defined(SPC5_ADC0_FIFO5_DMA_IRQ_PRIO) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_FIFO5_DMA_IRQ_PRIO 12
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief EQADC clock prescaler value.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_CR_CLK_PS) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_CR_CLK_PS ADC_CR_CLK_PS(5)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Initialization value for PUDCRx registers.
|
||||
*/
|
||||
#if !defined(SPC5_ADC_PUDCR) || defined(__DOXYGEN__)
|
||||
#define SPC5_ADC_PUDCR {ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE, \
|
||||
ADC_PUDCR_NONE}
|
||||
#endif
|
||||
/** @} */
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Derived constants and error checks. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if !SPC5_HAS_EQADC
|
||||
#error "EQADC not present in the selected device"
|
||||
#endif
|
||||
|
||||
#define SPC5_ADC_USE_ADC0 (SPC5_ADC_USE_ADC0_Q0 || \
|
||||
SPC5_ADC_USE_ADC0_Q1 || \
|
||||
SPC5_ADC_USE_ADC0_Q2)
|
||||
#define SPC5_ADC_USE_ADC1 (SPC5_ADC_USE_ADC1_Q3 || \
|
||||
SPC5_ADC_USE_ADC1_Q4 || \
|
||||
SPC5_ADC_USE_ADC1_Q5)
|
||||
|
||||
#if !SPC5_ADC_USE_ADC0 && !SPC5_ADC_USE_ADC1
|
||||
#error "ADC driver activated but no ADC peripheral assigned"
|
||||
#endif
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver data structures and types. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*!
|
||||
* @brief FIFO unit numeric IDs.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_FIFO_0 = 0,
|
||||
ADC_FIFO_1 = 1,
|
||||
ADC_FIFO_2 = 2,
|
||||
ADC_FIFO_3 = 3,
|
||||
ADC_FIFO_4 = 4,
|
||||
ADC_FIFO_5 = 5
|
||||
} adcfifo_t;
|
||||
|
||||
/**
|
||||
* @brief ADC command data type.
|
||||
*/
|
||||
typedef uint32_t adccommand_t;
|
||||
|
||||
/**
|
||||
* @brief ADC sample data type.
|
||||
*/
|
||||
typedef uint16_t adcsample_t;
|
||||
|
||||
/**
|
||||
* @brief Channels number in a conversion group.
|
||||
*/
|
||||
typedef uint16_t adc_channels_num_t;
|
||||
|
||||
/**
|
||||
* @brief Possible ADC failure causes.
|
||||
* @note Error codes are architecture dependent and should not relied
|
||||
* upon.
|
||||
*/
|
||||
typedef enum {
|
||||
ADC_ERR_DMAFAILURE = 0 /**< DMA operations failure. */
|
||||
} adcerror_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a structure representing an ADC driver.
|
||||
*/
|
||||
typedef struct ADCDriver ADCDriver;
|
||||
|
||||
/**
|
||||
* @brief ADC notification callback type.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object triggering the
|
||||
* callback
|
||||
* @param[in] buffer pointer to the most recent samples data
|
||||
* @param[in] n number of buffer rows available starting from @p buffer
|
||||
*/
|
||||
typedef void (*adccallback_t)(ADCDriver *adcp, adcsample_t *buffer, size_t n);
|
||||
|
||||
/**
|
||||
* @brief ADC error callback type.
|
||||
*
|
||||
* @param[in] adcp pointer to the @p ADCDriver object triggering the
|
||||
* callback
|
||||
* @param[in] err ADC error code
|
||||
*/
|
||||
typedef void (*adcerrorcallback_t)(ADCDriver *adcp, adcerror_t err);
|
||||
|
||||
/**
|
||||
* @brief Conversion group configuration structure.
|
||||
* @details This implementation-dependent structure describes a conversion
|
||||
* operation.
|
||||
* @note Implementations may extend this structure to contain more,
|
||||
* architecture dependent, fields.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief Enables the circular buffer mode for the group.
|
||||
*/
|
||||
bool_t circular;
|
||||
/**
|
||||
* @brief Number of the analog channels belonging to the conversion group.
|
||||
*/
|
||||
adc_channels_num_t num_channels;
|
||||
/**
|
||||
* @brief Callback function associated to the group or @p NULL.
|
||||
*/
|
||||
adccallback_t end_cb;
|
||||
/**
|
||||
* @brief Error callback or @p NULL.
|
||||
*/
|
||||
adcerrorcallback_t error_cb;
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief Initialization value for CFCR register.
|
||||
*/
|
||||
uint16_t cfcr;
|
||||
/**
|
||||
* @brief SIU ETISR.TSEL value for this queue;
|
||||
*/
|
||||
uint8_t tsel;
|
||||
/**
|
||||
* @brief SIU ISEL3.ETSEL value for this queue;
|
||||
*/
|
||||
uint8_t etsel;
|
||||
/**
|
||||
* @brief Number of command iterations stored in @p commands.
|
||||
* @note The total number of array elements must be @p num_channels *
|
||||
* @p num_iterations.
|
||||
* @note This fields is the upper limit of the parameter @p n that can
|
||||
* be passed to the functions @p adcConvert() and
|
||||
* @p adcStartConversion().
|
||||
*/
|
||||
uint32_t num_iterations;
|
||||
/**
|
||||
* @brief Pointer to an array of low level EQADC commands to be pushed
|
||||
* into the CFIFO during a conversion.
|
||||
*/
|
||||
const adccommand_t *commands;
|
||||
} ADCConversionGroup;
|
||||
|
||||
/**
|
||||
* @brief Driver configuration structure.
|
||||
* @note Empty in this implementation can be ignored.
|
||||
*/
|
||||
typedef struct {
|
||||
uint32_t dummy;
|
||||
} ADCConfig;
|
||||
|
||||
/**
|
||||
* @brief Structure representing an ADC driver.
|
||||
*/
|
||||
struct ADCDriver {
|
||||
/**
|
||||
* @brief Driver state.
|
||||
*/
|
||||
adcstate_t state;
|
||||
/**
|
||||
* @brief Current configuration data.
|
||||
*/
|
||||
const ADCConfig *config;
|
||||
/**
|
||||
* @brief Current samples buffer pointer or @p NULL.
|
||||
*/
|
||||
adcsample_t *samples;
|
||||
/**
|
||||
* @brief Current samples buffer depth or @p 0.
|
||||
*/
|
||||
size_t depth;
|
||||
/**
|
||||
* @brief Current conversion group pointer or @p NULL.
|
||||
*/
|
||||
const ADCConversionGroup *grpp;
|
||||
#if ADC_USE_WAIT || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Waiting thread.
|
||||
*/
|
||||
Thread *thread;
|
||||
#endif
|
||||
#if ADC_USE_MUTUAL_EXCLUSION || defined(__DOXYGEN__)
|
||||
#if CH_USE_MUTEXES || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Mutex protecting the peripheral.
|
||||
*/
|
||||
Mutex mutex;
|
||||
#elif CH_USE_SEMAPHORES
|
||||
Semaphore semaphore;
|
||||
#endif
|
||||
#endif /* ADC_USE_MUTUAL_EXCLUSION */
|
||||
#if defined(ADC_DRIVER_EXT_FIELDS)
|
||||
ADC_DRIVER_EXT_FIELDS
|
||||
#endif
|
||||
/* End of the mandatory fields.*/
|
||||
/**
|
||||
* @brief CFIFO/RFIFO used by this instance.
|
||||
*/
|
||||
adcfifo_t fifo;
|
||||
/**
|
||||
* @brief EDMA channel used for the CFIFO.
|
||||
*/
|
||||
edma_channel_t cfifo_channel;
|
||||
/**
|
||||
* @brief EDMA channel used for the RFIFO.
|
||||
*/
|
||||
edma_channel_t rfifo_channel;
|
||||
};
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver macros. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/*===========================================================================*/
|
||||
/* External declarations. */
|
||||
/*===========================================================================*/
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q0 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD1;
|
||||
#endif
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q1 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD2;
|
||||
#endif
|
||||
|
||||
#if SPC5_ADC_USE_ADC0_Q2 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD3;
|
||||
#endif
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q3 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD4;
|
||||
#endif
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q4 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD5;
|
||||
#endif
|
||||
|
||||
#if SPC5_ADC_USE_ADC1_Q5 && !defined(__DOXYGEN__)
|
||||
extern ADCDriver ADCD6;
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
void adc_lld_init(void);
|
||||
void adc_lld_start(ADCDriver *adcp);
|
||||
void adc_lld_stop(ADCDriver *adcp);
|
||||
void adc_lld_start_conversion(ADCDriver *adcp);
|
||||
void adc_lld_stop_conversion(ADCDriver *adcp);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAL_USE_ADC */
|
||||
|
||||
#endif /* _ADC_LLD_H_ */
|
||||
|
||||
/** @} */
|
||||
Reference in New Issue
Block a user