Driver for new ADC (SAADC) in NRF52 devices.
This commit is contained in:
parent
a6a380af6a
commit
7fa948e7c6
|
@ -0,0 +1,9 @@
|
||||||
|
ifeq ($(USE_SMART_BUILD),yes)
|
||||||
|
ifneq ($(findstring HAL_USE_ADC TRUE,$(HALCONF)),)
|
||||||
|
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/ADCv2/hal_adc_lld.c
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
PLATFORMSRC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/ADCv2/hal_adc_lld.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
PLATFORMINC_CONTRIB += ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/ADCv2
|
|
@ -0,0 +1,222 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Konstantin Oblaukhov
|
||||||
|
|
||||||
|
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 hal_adc_lld.c
|
||||||
|
* @brief NRF5 ADC subsystem low level driver source.
|
||||||
|
*
|
||||||
|
* @addtogroup ADC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "hal.h"
|
||||||
|
|
||||||
|
#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local definitions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported variables. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ADC1 driver identifier.
|
||||||
|
*/
|
||||||
|
#if (NRF5_ADC_USE_ADC1 == TRUE) || defined(__DOXYGEN__)
|
||||||
|
ADCDriver ADCD1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local variables and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver local functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver interrupt handlers. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if NRF5_ADC_USE_ADC1 || defined(__DOXYGEN__)
|
||||||
|
/**
|
||||||
|
* @brief ADC interrupt handler.
|
||||||
|
*
|
||||||
|
* @isr
|
||||||
|
*/
|
||||||
|
OSAL_IRQ_HANDLER(Vector5C) {
|
||||||
|
|
||||||
|
ADCDriver *adcp = &ADCD1;
|
||||||
|
NRF_SAADC_Type *adc = adcp->adc;
|
||||||
|
const ADCConversionGroup *grpp = adcp->grpp;
|
||||||
|
|
||||||
|
OSAL_IRQ_PROLOGUE();
|
||||||
|
|
||||||
|
if (adc->EVENTS_RESULTDONE) {
|
||||||
|
adc->EVENTS_RESULTDONE = 0;
|
||||||
|
adcp->ch_counter++;
|
||||||
|
|
||||||
|
if (adcp->ch_counter == grpp->num_channels) {
|
||||||
|
adcp->counter++;
|
||||||
|
adcp->ch_counter = 0;
|
||||||
|
|
||||||
|
if (grpp->circular &
|
||||||
|
(adcp->counter == adcp->depth / 2))
|
||||||
|
_adc_isr_half_code(adcp)
|
||||||
|
|
||||||
|
if ((adcp->counter < adcp->depth) && !grpp->external) {
|
||||||
|
adc->TASKS_SAMPLE = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adc->EVENTS_END) {
|
||||||
|
adc->EVENTS_END = 0;
|
||||||
|
_adc_isr_full_code(adcp);
|
||||||
|
|
||||||
|
if (grpp->circular) {
|
||||||
|
adcp->counter = 0;
|
||||||
|
adcp->ch_counter = 0;
|
||||||
|
adc->TASKS_START = 1;
|
||||||
|
if (!grpp->external)
|
||||||
|
adc->TASKS_SAMPLE = 1;
|
||||||
|
} else
|
||||||
|
adc_lld_stop_conversion(adcp);
|
||||||
|
}
|
||||||
|
|
||||||
|
OSAL_IRQ_EPILOGUE();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver exported functions. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level ADC driver initialization.
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void adc_lld_init(void) {
|
||||||
|
|
||||||
|
#if NRF5_ADC_USE_ADC1 == TRUE
|
||||||
|
/* Driver initialization.*/
|
||||||
|
adcObjectInit(&ADCD1);
|
||||||
|
ADCD1.adc = NRF_SAADC;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Configures and activates the ADC peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void adc_lld_start(ADCDriver *adcp) {
|
||||||
|
|
||||||
|
if (adcp->state == ADC_STOP) {
|
||||||
|
/* Enables the peripheral.*/
|
||||||
|
#if NRF5_ADC_USE_ADC1 == TRUE
|
||||||
|
if (&ADCD1 == adcp) {
|
||||||
|
adcp->adc->INTEN = SAADC_INTEN_END_Msk | SAADC_INTEN_RESULTDONE_Msk;
|
||||||
|
nvicEnableVector(SAADC_IRQn, NRF5_ADC_IRQ_PRIORITY);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/* Configures the peripheral.*/
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Deactivates the ADC peripheral.
|
||||||
|
*
|
||||||
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void adc_lld_stop(ADCDriver *adcp) {
|
||||||
|
|
||||||
|
if (adcp->state == ADC_READY) {
|
||||||
|
/* Resets the peripheral.*/
|
||||||
|
|
||||||
|
/* Disables the peripheral.*/
|
||||||
|
#if NRF5_ADC_USE_ADC1 == TRUE
|
||||||
|
if (&ADCD1 == adcp) {
|
||||||
|
nvicDisableVector(SAADC_IRQn);
|
||||||
|
adcp->adc->INTEN = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Starts an ADC conversion.
|
||||||
|
*
|
||||||
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void adc_lld_start_conversion(ADCDriver *adcp) {
|
||||||
|
NRF_SAADC_Type *adc = adcp->adc;
|
||||||
|
const ADCConversionGroup *grpp = adcp->grpp;
|
||||||
|
|
||||||
|
adc->RESOLUTION = grpp->resolution;
|
||||||
|
adc->OVERSAMPLE = grpp->oversample;
|
||||||
|
adc->SAMPLERATE = grpp->samplerate;
|
||||||
|
|
||||||
|
for (int i = 0; i < grpp->num_channels; i++) {
|
||||||
|
adc->CH[i].PSELP = grpp->channels[i].pselp;
|
||||||
|
adc->CH[i].PSELN = grpp->channels[i].pseln;
|
||||||
|
adc->CH[i].CONFIG = grpp->channels[i].config;
|
||||||
|
}
|
||||||
|
for (int i = grpp->num_channels; i < NRF5_ADC_MAX_CHANNELS; i++) {
|
||||||
|
adc->CH[i].PSELP = 0;
|
||||||
|
adc->CH[i].PSELN = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
adc->RESULT.PTR = (uint32_t)adcp->samples;
|
||||||
|
adc->RESULT.MAXCNT = adcp->depth * grpp->num_channels;
|
||||||
|
|
||||||
|
adcp->counter = 0;
|
||||||
|
adcp->ch_counter = 0;
|
||||||
|
|
||||||
|
adc->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
|
||||||
|
adc->TASKS_START = 1;
|
||||||
|
|
||||||
|
if (!grpp->external)
|
||||||
|
adc->TASKS_SAMPLE = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Stops an ongoing conversion.
|
||||||
|
*
|
||||||
|
* @param[in] adcp pointer to the @p ADCDriver object
|
||||||
|
*
|
||||||
|
* @notapi
|
||||||
|
*/
|
||||||
|
void adc_lld_stop_conversion(ADCDriver *adcp) {
|
||||||
|
NRF_SAADC_Type *adc = adcp->adc;
|
||||||
|
|
||||||
|
adc->TASKS_STOP = 1;
|
||||||
|
adc->ENABLE = SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAL_USE_ADC == TRUE */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
Copyright (C) 2020 Konstantin Oblaukhov
|
||||||
|
|
||||||
|
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 hal_adc_lld.h
|
||||||
|
* @brief NRF5 ADC subsystem low level driver header.
|
||||||
|
*
|
||||||
|
* @addtogroup ADC
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HAL_ADC_LLD_H
|
||||||
|
#define HAL_ADC_LLD_H
|
||||||
|
|
||||||
|
#if (HAL_USE_ADC == TRUE) || defined(__DOXYGEN__)
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver constants. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver pre-compile time settings. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @name NRF5 configuration options
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
/**
|
||||||
|
* @brief ADC1 driver enable switch.
|
||||||
|
* @details If set to @p TRUE the support for ADC1 is included.
|
||||||
|
* @note The default is @p FALSE.
|
||||||
|
*/
|
||||||
|
#if !defined(NRF5_ADC_USE_ADC1) || defined(__DOXYGEN__)
|
||||||
|
#define NRF5_ADC_USE_ADC1 FALSE
|
||||||
|
#endif
|
||||||
|
/** @} */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ADC interrupt priority level setting.
|
||||||
|
*/
|
||||||
|
#if !defined(NRF5_ADC_IRQ_PRIORITY) || defined(__DOXYGEN__)
|
||||||
|
#define NRF5_ADC_IRQ_PRIORITY (CORTEX_MAX_KERNEL_PRIORITY + 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Derived constants and error checks. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if !NRF5_ADC_USE_ADC1
|
||||||
|
#error "ADC driver activated but no ADC peripheral assigned"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(NRF5_ADC_MAX_CHANNELS) || defined(__DOXYGEN__)
|
||||||
|
#define NRF5_ADC_MAX_CHANNELS 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver data structures and types. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ADC sample data type.
|
||||||
|
*/
|
||||||
|
typedef uint16_t adcsample_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Channels number in a conversion group.
|
||||||
|
*/
|
||||||
|
typedef uint8_t adc_channels_num_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Possible ADC failure causes.
|
||||||
|
* @note Error codes are architecture dependent and should not relied
|
||||||
|
* upon.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ADC_ERR_DMAFAILURE = 0, /**< DMA operations failure. */
|
||||||
|
ADC_ERR_OVERFLOW = 1, /**< ADC overflow condition. */
|
||||||
|
} adcerror_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief ADC channel config.
|
||||||
|
*/
|
||||||
|
struct adc_lld_channel_config {
|
||||||
|
/* @brief ADC channel positive pin.*/
|
||||||
|
uint8_t pselp;
|
||||||
|
/* @brief ADC channel negative pin.*/
|
||||||
|
uint8_t pseln;
|
||||||
|
/* @brief ADC channel CONFIG register details.*/
|
||||||
|
uint32_t config;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* Driver macros. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level fields of the ADC driver structure.
|
||||||
|
*/
|
||||||
|
#define adc_lld_driver_fields \
|
||||||
|
/* @brief Pointer to the ADCx registers block.*/ \
|
||||||
|
NRF_SAADC_Type *adc; \
|
||||||
|
/* @brief Current sample counter.*/ \
|
||||||
|
size_t counter; \
|
||||||
|
/* @brief Current channel counter.*/ \
|
||||||
|
size_t ch_counter
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level fields of the ADC configuration structure.
|
||||||
|
*/
|
||||||
|
#define adc_lld_config_fields \
|
||||||
|
/* Dummy configuration, it is not needed.*/ \
|
||||||
|
uint32_t dummy
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Low level fields of the ADC configuration structure.
|
||||||
|
*/
|
||||||
|
#define adc_lld_configuration_group_fields \
|
||||||
|
/* @brief ADC sample is triggered by external source.*/ \
|
||||||
|
bool external; \
|
||||||
|
/* @brief ADC RESOLUTION register details.*/ \
|
||||||
|
uint32_t resolution; \
|
||||||
|
/* @brief ADC OVERSAMPLE register details.*/ \
|
||||||
|
uint32_t oversample; \
|
||||||
|
/* @brief ADC SAMPLERATE register details.*/ \
|
||||||
|
uint32_t samplerate; \
|
||||||
|
/* @brief ADC channel configurations.*/ \
|
||||||
|
struct adc_lld_channel_config channels[NRF5_ADC_MAX_CHANNELS]
|
||||||
|
|
||||||
|
/*===========================================================================*/
|
||||||
|
/* External declarations. */
|
||||||
|
/*===========================================================================*/
|
||||||
|
|
||||||
|
#if (NRF5_ADC_USE_ADC1 == TRUE) && !defined(__DOXYGEN__)
|
||||||
|
extern ADCDriver ADCD1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
void adc_lld_init(void);
|
||||||
|
void adc_lld_start(ADCDriver *adcp);
|
||||||
|
void adc_lld_stop(ADCDriver *adcp);
|
||||||
|
void adc_lld_start_conversion(ADCDriver *adcp);
|
||||||
|
void adc_lld_stop_conversion(ADCDriver *adcp);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* HAL_USE_ADC == TRUE */
|
||||||
|
|
||||||
|
#endif /* HAL_ADC_LLD_H */
|
||||||
|
|
||||||
|
/** @} */
|
|
@ -18,6 +18,7 @@ HALCONF := $(strip $(shell cat $(CONFDIR)/halconf.h $(CONFDIR)/halconf_community
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/ADCv2/driver.mk
|
||||||
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/GPIOv1/driver.mk
|
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/GPIOv1/driver.mk
|
||||||
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/UARTv1/driver.mk
|
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/UARTv1/driver.mk
|
||||||
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/SPIv1/driver.mk
|
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/SPIv1/driver.mk
|
||||||
|
|
Loading…
Reference in New Issue