Driver for new ADC (SAADC) in NRF52 devices.

This commit is contained in:
Konstantin Oblaukhov 2020-01-12 13:34:28 +07:00
parent a6a380af6a
commit 7fa948e7c6
4 changed files with 400 additions and 0 deletions

View File

@ -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

View File

@ -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 */
/** @} */

View File

@ -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 */
/** @} */

View File

@ -18,6 +18,7 @@ HALCONF := $(strip $(shell cat $(CONFDIR)/halconf.h $(CONFDIR)/halconf_community
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/UARTv1/driver.mk
include ${CHIBIOS_CONTRIB}/os/hal/ports/NRF5/LLD/SPIv1/driver.mk