mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
cpu/sam0_common: implement periph_adc_continous
This commit is contained in:
parent
2421919295
commit
b289d69b4f
@ -8,6 +8,7 @@
|
||||
config CPU_COMMON_SAM0
|
||||
bool
|
||||
select HAS_PERIPH_CPUID
|
||||
select HAS_PERIPH_ADC_CONTINUOUS
|
||||
select HAS_PERIPH_FLASHPAGE
|
||||
select HAS_PERIPH_FLASHPAGE_IN_ADDRESS_SPACE
|
||||
select HAS_PERIPH_FLASHPAGE_PAGEWISE
|
||||
|
@ -7,6 +7,7 @@ ifeq (,$(filter $(CPU_MODELS_WITHOUT_DMA),$(CPU_MODEL)))
|
||||
FEATURES_PROVIDED += periph_dma
|
||||
endif
|
||||
|
||||
FEATURES_PROVIDED += periph_adc_continuous
|
||||
FEATURES_PROVIDED += periph_flashpage
|
||||
FEATURES_PROVIDED += periph_flashpage_in_address_space
|
||||
FEATURES_PROVIDED += periph_flashpage_pagewise
|
||||
|
@ -49,16 +49,6 @@ static int _adc_configure(Adc *dev, adc_res_t res);
|
||||
|
||||
static mutex_t _lock = MUTEX_INIT;
|
||||
|
||||
static inline void _prep(void)
|
||||
{
|
||||
mutex_lock(&_lock);
|
||||
}
|
||||
|
||||
static inline void _done(void)
|
||||
{
|
||||
mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
static inline void _wait_syncbusy(Adc *dev)
|
||||
{
|
||||
#ifdef ADC_STATUS_SYNCBUSY
|
||||
@ -263,7 +253,7 @@ int adc_init(adc_t line)
|
||||
const uint8_t adc = 0;
|
||||
#endif
|
||||
|
||||
_prep();
|
||||
mutex_lock(&_lock);
|
||||
|
||||
uint8_t muxpos = (adc_channels[line].inputctrl & ADC_INPUTCTRL_MUXPOS_Msk)
|
||||
>> ADC_INPUTCTRL_MUXPOS_Pos;
|
||||
@ -284,34 +274,44 @@ int adc_init(adc_t line)
|
||||
gpio_init_mux(sam0_adc_pins[adc][muxneg], GPIO_MUX_B);
|
||||
}
|
||||
|
||||
_done();
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t adc_sample(adc_t line, adc_res_t res)
|
||||
static Adc *_dev(adc_t line)
|
||||
{
|
||||
if (line >= ADC_NUMOF) {
|
||||
DEBUG("adc: line arg not applicable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
|
||||
#ifdef ADC0
|
||||
Adc *dev = adc_channels[line].dev;
|
||||
return adc_channels[line].dev;
|
||||
#else
|
||||
Adc *dev = ADC;
|
||||
(void)line;
|
||||
return ADC;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
|
||||
|
||||
_prep();
|
||||
|
||||
if (_adc_configure(dev, res) != 0) {
|
||||
_done();
|
||||
DEBUG("adc: configuration failed\n");
|
||||
return -1;
|
||||
static Adc *_adc(uint8_t dev)
|
||||
{
|
||||
/* The SAMD5x/SAME5x family has two ADCs: ADC0 and ADC1. */
|
||||
#ifdef ADC0
|
||||
switch (dev) {
|
||||
case 0:
|
||||
return ADC0;
|
||||
case 1:
|
||||
return ADC1;
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
(void)dev;
|
||||
return ADC;
|
||||
#endif
|
||||
}
|
||||
|
||||
static int32_t _sample(adc_t line)
|
||||
{
|
||||
Adc *dev = _dev(line);
|
||||
bool diffmode = adc_channels[line].inputctrl & ADC_INPUTCTRL_DIFFMODE;
|
||||
|
||||
dev->INPUTCTRL.reg = ADC_GAIN_FACTOR_DEFAULT
|
||||
| adc_channels[line].inputctrl
|
||||
@ -319,7 +319,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
||||
#ifdef ADC_CTRLB_DIFFMODE
|
||||
dev->CTRLB.bit.DIFFMODE = diffmode;
|
||||
#endif
|
||||
|
||||
_wait_syncbusy(dev);
|
||||
|
||||
/* Start the conversion */
|
||||
@ -331,9 +330,6 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
||||
uint16_t sample = dev->RESULT.reg;
|
||||
int result;
|
||||
|
||||
_adc_poweroff(dev);
|
||||
_done();
|
||||
|
||||
/* in differential mode we lose one bit for the sign */
|
||||
if (diffmode) {
|
||||
result = 2 * (int16_t)sample;
|
||||
@ -341,11 +337,102 @@ int32_t adc_sample(adc_t line, adc_res_t res)
|
||||
result = sample;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static uint8_t _shift_from_res(adc_res_t res)
|
||||
{
|
||||
/* 16 bit mode is implemented as oversampling */
|
||||
if ((res & 0x3) == 1) {
|
||||
/* ADC does automatic right shifts beyond 16 samples */
|
||||
result <<= (4 - MIN(4, res >> 2));
|
||||
return 4 - MIN(4, res >> 2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void _get_adcs(bool *adc0, bool *adc1)
|
||||
{
|
||||
#ifndef ADC1
|
||||
*adc0 = true;
|
||||
*adc1 = false;
|
||||
return;
|
||||
#else
|
||||
for (unsigned i = 0; i < ADC_NUMOF; ++i) {
|
||||
if (adc_channels[i].dev == ADC0) {
|
||||
*adc0 = true;
|
||||
} else if (adc_channels[i].dev == ADC1) {
|
||||
*adc1 = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t _shift;
|
||||
void adc_continuous_begin(adc_res_t res)
|
||||
{
|
||||
bool adc0, adc1;
|
||||
_get_adcs(&adc0, &adc1);
|
||||
|
||||
mutex_lock(&_lock);
|
||||
|
||||
if (adc0) {
|
||||
_adc_configure(_adc(0), res);
|
||||
}
|
||||
if (adc1) {
|
||||
_adc_configure(_adc(1), res);
|
||||
}
|
||||
|
||||
return result;
|
||||
_shift = _shift_from_res(res);
|
||||
}
|
||||
|
||||
int32_t adc_continuous_sample(adc_t line)
|
||||
{
|
||||
int val;
|
||||
assert(line < ADC_NUMOF);
|
||||
|
||||
mutex_lock(&_lock);
|
||||
val = _sample(line) << _shift;
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void adc_continuous_stop(void)
|
||||
{
|
||||
bool adc0, adc1;
|
||||
_get_adcs(&adc0, &adc1);
|
||||
|
||||
if (adc0) {
|
||||
_adc_poweroff(_adc(0));
|
||||
}
|
||||
if (adc1) {
|
||||
_adc_poweroff(_adc(1));
|
||||
}
|
||||
|
||||
mutex_unlock(&_lock);
|
||||
}
|
||||
|
||||
int32_t adc_sample(adc_t line, adc_res_t res)
|
||||
{
|
||||
if (line >= ADC_NUMOF) {
|
||||
DEBUG("adc: line arg not applicable\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
mutex_lock(&_lock);
|
||||
|
||||
Adc *dev = _dev(line);
|
||||
|
||||
if (_adc_configure(dev, res) != 0) {
|
||||
DEBUG("adc: configuration failed\n");
|
||||
mutex_unlock(&_lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int val = _sample(line) << _shift_from_res(res);
|
||||
|
||||
_adc_poweroff(dev);
|
||||
mutex_unlock(&_lock);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user