Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cpu/efm32: add periph_adc support for Gecko Series 2 #18933

Merged
merged 2 commits into from
Nov 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions boards/xg23-pk6068a/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ config BOARD_XG23_PK6068A
select CPU_MODEL_EFR32ZG23A020F512GM48

# Put defined MCU peripherals here (in alphabetical order)
select HAS_PERIPH_ADC
select HAS_PERIPH_I2C
select HAS_PERIPH_SPI
select HAS_PERIPH_TIMER
Expand Down
1 change: 1 addition & 0 deletions boards/xg23-pk6068a/Makefile.features
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ CPU_FAM = efr32zg23
CPU_MODEL = efr32zg23a020f512gm48

# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_adc
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_timer
Expand Down
2 changes: 2 additions & 0 deletions boards/xg23-pk6068a/doc.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ PIN 1 is the bottom-left contact when the header faces you horizontally.
| Timer | 0 | TIMER0 | | Default ztimer backend | EM1 |
| | 1 | LETIMER0 | | | EM3 |
| UART | 0 | EUSART1 | RX: PA9, TX: PA8 | Default STDIO output | EM1 |
| ADC_LINE | 0 | IADC0 | IN+: PA10, IN-: GND | Single-ended, V_ref: 2 * 1.21V | EM1 |
| | 1 | IADC0 | IN+: PA0, IN-:PA5 | Differential, V_ref: 2 * 1.21V | EM1 |

### User interface
| Peripheral | Mapped to | Pin | Comments |
Expand Down
32 changes: 32 additions & 0 deletions boards/xg23-pk6068a/include/periph_conf.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,38 @@ static const clk_div_t clk_div_config[] = {
#define CLK_DIV_NUMOF ARRAY_SIZE(clk_div_config)
/** @} */

/**
* @name ADC configuration
* @{
*/
static const adc_conf_t adc_config[] = {
{
.dev = IADC0,
.cmu = cmuClock_IADC0,
.reference = iadcCfgReferenceInt1V2,
.reference_mV = 1210,
.gain = iadcCfgAnalogGain0P5x,
.available_res = { ADC_RES_10BIT, ADC_RES_16BIT }
}
};

static const adc_chan_conf_t adc_channel_config[] = {
{
.dev = 0,
.input_pos = GPIO_PIN(PA, 10),
.input_neg = GPIO_UNDEF
},
{
.dev = 0,
.input_pos = GPIO_PIN(PA, 0),
.input_neg = GPIO_PIN(PA, 5)
},
};

#define ADC_DEV_NUMOF ARRAY_SIZE(adc_config)
#define ADC_NUMOF ARRAY_SIZE(adc_channel_config)
/** @} */

/**
* @name I2C configuration
* @{
Expand Down
232 changes: 181 additions & 51 deletions cpu/efm32/include/periph_cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@

#include "cpu_conf.h"

#if defined(_SILICON_LABS_32B_SERIES_2)
#include "em_iadc.h"
#else
#include "em_adc.h"
#endif
#include "em_cmu.h"
#include "em_device.h"
#include "em_gpio.h"
Expand Down Expand Up @@ -57,57 +61,6 @@ typedef struct {
CMU_ClkDiv_TypeDef div; /**< Divisor */
} clk_div_t;

#if (defined(ADC_COUNT) && (ADC_COUNT > 0)) || defined(DOXYGEN)
/**
* @brief Internal macro for combining ADC resolution (x) with number of
* shifts (y).
*/
#define ADC_MODE(x, y) ((y << 4) | x)

/**
* @brief Internal define to note that resolution is not supported.
*/
#define ADC_MODE_UNDEF(x) (ADC_MODE(x, 15))

#ifndef DOXYGEN
/**
* @brief Possible ADC resolution settings
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = ADC_MODE(adcRes6Bit, 0), /**< ADC resolution: 6 bit */
ADC_RES_8BIT = ADC_MODE(adcRes8Bit, 0), /**< ADC resolution: 8 bit */
ADC_RES_10BIT = ADC_MODE(adcRes12Bit, 2), /**< ADC resolution: 10 bit (shifted from 12 bit) */
ADC_RES_12BIT = ADC_MODE(adcRes12Bit, 0), /**< ADC resolution: 12 bit */
ADC_RES_14BIT = ADC_MODE_UNDEF(0), /**< ADC resolution: 14 bit (unsupported) */
ADC_RES_16BIT = ADC_MODE_UNDEF(1), /**< ADC resolution: 16 bit (unsupported) */
} adc_res_t;
/** @} */
#endif /* ndef DOXYGEN */

/**
* @brief ADC device configuration
*/
typedef struct {
ADC_TypeDef *dev; /**< ADC device used */
CMU_Clock_TypeDef cmu; /**< the device CMU channel */
} adc_conf_t;

/**
* @brief ADC channel configuration
*/
typedef struct {
uint8_t dev; /**< device index */
#if defined(_SILICON_LABS_32B_SERIES_0)
ADC_SingleInput_TypeDef input; /**< input channel */
#elif defined(_SILICON_LABS_32B_SERIES_1)
ADC_PosSel_TypeDef input; /**< input channel */
#endif
ADC_Ref_TypeDef reference; /**< channel voltage reference */
ADC_AcqTime_TypeDef acq_time; /**< channel acquisition time */
} adc_chan_conf_t;
#endif

/**
* @brief Length of CPU ID in octets.
Expand Down Expand Up @@ -245,6 +198,183 @@ typedef enum {
/** @} */
#endif /* ndef DOXYGEN */

#if defined(_SILICON_LABS_32B_SERIES_2)
/**
* @brief Internal macro for combining over-sampling rate (osr), digital
* averaging count (avg) and output resolution (res).
*
* @note The efr32xg23 reference manual provides this folumar:
* res = 11 bit + log_2(osr * avg) bit
*/
#if defined(_IADC_CFG_DIGAVG_MASK)
#define ADC_MODE(osr, avg, res) ((osr << 16) | (avg << 8) | res)
#else
#define ADC_MODE(osr, res) ((osr << 16) | res)
#endif

/**
* @brief Internal macro to extract averaging count
*/
#define ADC_MODE_OSR(mode) ((mode & 0xff0000) >> 16)

#if defined(_IADC_CFG_DIGAVG_MASK)
/**
* @brief Internal macro to extract over-sampling rate
*/
#define ADC_MODE_AVG(mode) ((mode & 0x00ff00) >> 8)
#endif

/**
* @brief Internal macro to extract output resolution
*/
#define ADC_MODE_RES(mode) ((mode & 0x0000ff) >> 0)

/**
* @brief Possible ADC resolution settings
* @{
*/
#define HAVE_ADC_RES_T
#if defined(_IADC_CFG_DIGAVG_MASK)
typedef enum {
ADC_RES_6BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, iadcDigitalAverage1, 6),
ADC_RES_8BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, iadcDigitalAverage1, 8),
ADC_RES_10BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, iadcDigitalAverage1, 10),
ADC_RES_12BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, iadcDigitalAverage1, 12),
ADC_RES_14BIT = ADC_MODE(iadcCfgOsrHighSpeed8x, iadcDigitalAverage1, 14),
ADC_RES_16BIT = ADC_MODE(iadcCfgOsrHighSpeed16x, iadcDigitalAverage2, 16),
} adc_res_t;
#else
typedef enum {
ADC_RES_6BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, 6),
ADC_RES_8BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, 8),
ADC_RES_10BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, 10),
ADC_RES_12BIT = ADC_MODE(iadcCfgOsrHighSpeed2x, 12),
ADC_RES_14BIT = ADC_MODE(iadcCfgOsrHighSpeed8x, 14),
ADC_RES_16BIT = ADC_MODE(iadcCfgOsrHighSpeed32x, 16),
} adc_res_t;
#endif

/**
* @brief ADC device configuration
*/
typedef struct {
/**
* IADC device configuration
*/
IADC_TypeDef *dev;

/**
* CMU gate for the IADC device
*/
CMU_Clock_TypeDef cmu;

/**
* Voltage reference to use
*/
IADC_CfgReference_t reference;

/**
* Voltage of the reference in mV
*
* @note Required internally for offset correction.
*/
uint32_t reference_mV;

/**
* Ampilfication of the analog input signal
*
* @note The maximum input voltage is
* \ref adc_conf_t.gain * \ref adc_conf_t.reference_mV
*/
IADC_CfgAnalogGain_t gain;

/**
* Available resoltions
*
* @note Resolutions made available to the applications have to be
* specified during \ref adc_init. This will configure the IADC
* accordingly and allows for quick \ref adc_sample calls.
*/
adc_res_t available_res[IADC0_CONFIGNUM];
} adc_conf_t;

/**
* @brief ADC channel configuration
*/
typedef struct {
/**
* \ref adc_conf_t device index
*/
uint8_t dev;

/**
* Positive analog input
*/
gpio_t input_pos;

/**
* Negative analog input.
* Can be set to \ref GPIO_UNDEF for single-ended ADC lines.
*
* @note For differential inputs make sure that
* \ref adc_chan_conf_t.input_pos is an even pin number and
* \ref adc_chan_conf_t.input_neg is an odd pin number or the other
* way around.
benpicco marked this conversation as resolved.
Show resolved Hide resolved
*/
gpio_t input_neg;
} adc_chan_conf_t;
#else /* defined(_SILICON_LABS_32B_SERIES_2) */
/**
* @brief Internal macro for combining ADC resolution (x) with number of
* shifts (y).
*/
#define ADC_MODE(x, y) ((y << 4) | x)

/**
* @brief Internal define to note that resolution is not supported.
*/
#define ADC_MODE_UNDEF(x) (ADC_MODE(x, 15))

#ifndef DOXYGEN
/**
* @brief Possible ADC resolution settings
* @{
*/
#define HAVE_ADC_RES_T
typedef enum {
ADC_RES_6BIT = ADC_MODE(adcRes6Bit, 0), /**< ADC resolution: 6 bit */
ADC_RES_8BIT = ADC_MODE(adcRes8Bit, 0), /**< ADC resolution: 8 bit */
ADC_RES_10BIT = ADC_MODE(adcRes12Bit, 2), /**< ADC resolution: 10 bit (shifted from 12 bit) */
ADC_RES_12BIT = ADC_MODE(adcRes12Bit, 0), /**< ADC resolution: 12 bit */
ADC_RES_14BIT = ADC_MODE_UNDEF(0), /**< ADC resolution: 14 bit (unsupported) */
ADC_RES_16BIT = ADC_MODE_UNDEF(1), /**< ADC resolution: 16 bit (unsupported) */
} adc_res_t;
/** @} */
#endif /* ndef DOXYGEN */

/**
* @brief ADC device configuration
*/
typedef struct {
ADC_TypeDef *dev; /**< ADC device used */
CMU_Clock_TypeDef cmu; /**< the device CMU channel */
} adc_conf_t;

/**
* @brief ADC channel configuration
*/
typedef struct {
uint8_t dev; /**< device index */
#if defined(_SILICON_LABS_32B_SERIES_0)
ADC_SingleInput_TypeDef input; /**< input channel */
#elif defined(_SILICON_LABS_32B_SERIES_1)
ADC_PosSel_TypeDef input; /**< input channel */
#endif
ADC_Ref_TypeDef reference; /**< channel voltage reference */
ADC_AcqTime_TypeDef acq_time; /**< channel acquisition time */
} adc_chan_conf_t;
#endif /* !defined(_SILICON_LABS_32B_SERIES_2) */

/**
* @brief Override hardware crypto supported methods.
* @{
Expand Down
9 changes: 9 additions & 0 deletions cpu/efm32/periph/Makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
include $(RIOTCPU)/efm32/efm32-info.mk

# Select the correct implementation for `periph_adc`
ifneq (,$(filter periph_adc,$(USEMODULE)))
ifeq (2,$(EFM32_SERIES))
SRC += adc_series2.c
else
SRC += adc_series01.c
endif
endif

# Select the correct implementation for `periph_timer`
ifneq (,$(filter periph_hwrng,$(USEMODULE)))
ifeq (1,$(EFM32_SERIES))
Expand Down
File renamed without changes.
Loading