nrf: Rewrite the AnalogIn common-hal using nrfx

This commit is contained in:
arturo182 2018-06-27 19:55:26 +02:00
parent 91427b0b23
commit 2a12fcd18b
6 changed files with 48 additions and 383 deletions

View File

@ -95,8 +95,6 @@ SRC_HAL = $(addprefix hal/,\
hal_time.c \
hal_timer.c \
hal_twi.c \
hal_adc.c \
hal_adce.c \
hal_gpio.c \
hal_rng.c \
hal_pwm.c \

View File

@ -4,6 +4,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2016 Scott Shawcroft for Adafruit Industries
* Copyright (c) 2018 Artur Pacholec
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@ -25,24 +26,19 @@
*/
#include "common-hal/analogio/AnalogIn.h"
#include <string.h>
#include "py/gc.h"
#include "py/nlr.h"
#include "py/runtime.h"
#include "py/binary.h"
#include "py/mphal.h"
#include "shared-bindings/analogio/AnalogIn.h"
#include "nrf.h"
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t* self, const mcu_pin_obj_t *pin) {
if (!pin->adc_channel) {
// No ADC function on that pin
#include "nrfx_saadc.h"
#include "nrf_gpio.h"
#define CHANNEL_NO 0
void common_hal_analogio_analogin_construct(analogio_analogin_obj_t *self, const mcu_pin_obj_t *pin) {
if (pin->adc_channel == 0)
mp_raise_ValueError("Pin does not have ADC capabilities");
}
hal_gpio_cfg_pin(pin->port, pin->pin, HAL_GPIO_MODE_INPUT, HAL_GPIO_PULL_DISABLED);
self->pin = pin;
}
@ -51,66 +47,61 @@ bool common_hal_analogio_analogin_deinited(analogio_analogin_obj_t *self) {
}
void common_hal_analogio_analogin_deinit(analogio_analogin_obj_t *self) {
if (common_hal_analogio_analogin_deinited(self)) {
if (common_hal_analogio_analogin_deinited(self))
return;
}
reset_pin(self->pin->pin);
nrf_gpio_cfg_default(NRF_GPIO_PIN_MAP(self->pin->port, self->pin->pin));
self->pin = mp_const_none;
}
void analogin_reset() {
}
uint16_t common_hal_analogio_analogin_get_value(analogio_analogin_obj_t *self) {
// Something else might have used the ADC in a different way,
// so we completely re-initialize it.
// Something else might have used the ADC in a different way,
// so we completely re-initialize it.
int16_t value;
nrf_saadc_value_t value;
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_14bit;
NRF_SAADC->ENABLE = 1;
const nrf_saadc_channel_config_t config = {
.resistor_p = NRF_SAADC_RESISTOR_DISABLED,
.resistor_n = NRF_SAADC_RESISTOR_DISABLED,
.gain = NRF_SAADC_GAIN1_6,
.reference = NRF_SAADC_REFERENCE_INTERNAL,
.acq_time = NRF_SAADC_ACQTIME_3US,
.mode = NRF_SAADC_MODE_SINGLE_ENDED,
.burst = NRF_SAADC_BURST_DISABLED,
.pin_p = self->pin->adc_channel,
.pin_n = self->pin->adc_channel,
};
for (int i = 0; i < 8; i++) {
NRF_SAADC->CH[i].PSELN = SAADC_CH_PSELP_PSELP_NC;
NRF_SAADC->CH[i].PSELP = SAADC_CH_PSELP_PSELP_NC;
}
nrf_saadc_resolution_set(NRF_SAADC_RESOLUTION_14BIT);
nrf_saadc_oversample_set(NRF_SAADC_OVERSAMPLE_DISABLED);
nrf_saadc_enable();
NRF_SAADC->CH[0].CONFIG = ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos) & SAADC_CH_CONFIG_RESP_Msk)
| ((SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESN_Pos) & SAADC_CH_CONFIG_RESN_Msk)
| ((SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) & SAADC_CH_CONFIG_GAIN_Msk)
| ((SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) & SAADC_CH_CONFIG_REFSEL_Msk)
| ((SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) & SAADC_CH_CONFIG_TACQ_Msk)
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
NRF_SAADC->CH[0].PSELN = self->pin->adc_channel;
NRF_SAADC->CH[0].PSELP = self->pin->adc_channel;
for (uint32_t i = 0; i < NRF_SAADC_CHANNEL_COUNT; i++)
nrf_saadc_channel_input_set(i, NRF_SAADC_INPUT_DISABLED, NRF_SAADC_INPUT_DISABLED);
nrf_saadc_channel_init(CHANNEL_NO, &config);
nrf_saadc_buffer_init(&value, 1);
NRF_SAADC->RESULT.PTR = (uint32_t)&value;
NRF_SAADC->RESULT.MAXCNT = 1;
nrf_saadc_task_trigger(NRF_SAADC_TASK_START);
while (nrf_saadc_event_check(NRF_SAADC_EVENT_STARTED) == 0);
nrf_saadc_event_clear(NRF_SAADC_EVENT_STARTED);
NRF_SAADC->TASKS_START = 0x01UL;
nrf_saadc_task_trigger(NRF_SAADC_TASK_SAMPLE);
while (nrf_saadc_event_check(NRF_SAADC_EVENT_END) == 0);
nrf_saadc_event_clear(NRF_SAADC_EVENT_END);
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
nrf_saadc_task_trigger(NRF_SAADC_TASK_STOP);
while (nrf_saadc_event_check(NRF_SAADC_EVENT_STOPPED) == 0);
nrf_saadc_event_clear(NRF_SAADC_EVENT_STOPPED);
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
nrf_saadc_disable();
while (!NRF_SAADC->EVENTS_END);
NRF_SAADC->EVENTS_END = 0x00UL;
if (value < 0)
value = 0;
NRF_SAADC->TASKS_STOP = 0x01UL;
while (!NRF_SAADC->EVENTS_STOPPED);
NRF_SAADC->EVENTS_STOPPED = 0x00UL;
if (value < 0) {
value = 0;
}
NRF_SAADC->ENABLE = 0;
// Map value to from 14 to 16 bits
return (value << 2);
// Map value to from 14 to 16 bits
return (value << 2);
}
float common_hal_analogio_analogin_get_reference_voltage(analogio_analogin_obj_t *self) {

View File

@ -36,6 +36,4 @@ typedef struct {
const mcu_pin_obj_t * pin;
} analogio_analogin_obj_t;
void analogin_reset(void);
#endif // MICROPY_INCLUDED_NRF_COMMON_HAL_ANALOGIO_ANALOGIN_H

View File

@ -1,129 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <stdio.h>
#include "mphalport.h"
#include "hal_adc.h"
#ifdef HAL_ADC_MODULE_ENABLED
#define ADC_REF_VOLTAGE_IN_MILLIVOLTS (1200) // Reference voltage (in milli volts) used by ADC while doing conversion.
#define ADC_PRE_SCALING_COMPENSATION (3) // The ADC is configured to use VDD with 1/3 prescaling as input. And hence the result of conversion is to be multiplied by 3 to get the actual value of the battery voltage.
#define DIODE_FWD_VOLT_DROP_MILLIVOLTS (270) // Typical forward voltage drop of the diode (Part no: SD103ATW-7-F) that is connected in series with the voltage supply. This is the voltage drop when the forward current is 1mA. Source: Data sheet of 'SURFACE MOUNT SCHOTTKY BARRIER DIODE ARRAY' available at www.diodes.com.
#define ADC_RESULT_IN_MILLI_VOLTS(ADC_VALUE)\
((((ADC_VALUE) * ADC_REF_VOLTAGE_IN_MILLIVOLTS) / 255) * ADC_PRE_SCALING_COMPENSATION)
static const uint32_t hal_adc_input_lookup[] = {
ADC_CONFIG_PSEL_AnalogInput0 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput1 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput2 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput3 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput4 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput5 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput6 << ADC_CONFIG_PSEL_Pos,
ADC_CONFIG_PSEL_AnalogInput7 << ADC_CONFIG_PSEL_Pos
};
static uint8_t battery_level_in_percent(const uint16_t mvolts)
{
uint8_t battery_level;
if (mvolts >= 3000) {
battery_level = 100;
} else if (mvolts > 2900) {
battery_level = 100 - ((3000 - mvolts) * 58) / 100;
} else if (mvolts > 2740) {
battery_level = 42 - ((2900 - mvolts) * 24) / 160;
} else if (mvolts > 2440) {
battery_level = 18 - ((2740 - mvolts) * 12) / 300;
} else if (mvolts > 2100) {
battery_level = 6 - ((2440 - mvolts) * 6) / 340;
} else {
battery_level = 0;
}
return battery_level;
}
uint16_t hal_adc_channel_value(hal_adc_config_t const * p_adc_conf) {
ADC_BASE->INTENSET = ADC_INTENSET_END_Msk;
ADC_BASE->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos)
| (ADC_CONFIG_INPSEL_AnalogInputTwoThirdsPrescaling << ADC_CONFIG_INPSEL_Pos)
| (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos)
| (hal_adc_input_lookup[p_adc_conf->channel])
| (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
ADC_BASE->EVENTS_END = 0;
ADC_BASE->ENABLE = ADC_ENABLE_ENABLE_Enabled;
ADC_BASE->EVENTS_END = 0;
ADC_BASE->TASKS_START = 1;
while (!ADC_BASE->EVENTS_END) {
;
}
uint8_t adc_result;
ADC_BASE->EVENTS_END = 0;
adc_result = ADC_BASE->RESULT;
ADC_BASE->TASKS_STOP = 1;
return adc_result;
}
uint16_t hal_adc_battery_level(void) {
ADC_BASE->INTENSET = ADC_INTENSET_END_Msk;
ADC_BASE->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos)
| (ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos)
| (ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos)
| (ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos)
| (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos);
ADC_BASE->EVENTS_END = 0;
ADC_BASE->ENABLE = ADC_ENABLE_ENABLE_Enabled;
ADC_BASE->EVENTS_END = 0;
ADC_BASE->TASKS_START = 1;
while (!ADC_BASE->EVENTS_END) {
;
}
uint8_t adc_result;
uint16_t batt_lvl_in_milli_volts;
ADC_BASE->EVENTS_END = 0;
adc_result = ADC_BASE->RESULT;
ADC_BASE->TASKS_STOP = 1;
batt_lvl_in_milli_volts = ADC_RESULT_IN_MILLI_VOLTS(adc_result) + DIODE_FWD_VOLT_DROP_MILLIVOLTS;
return battery_level_in_percent(batt_lvl_in_milli_volts);
}
#endif // HAL_ADC_MODULE_ENABLED

View File

@ -1,75 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef HAL_ADC_H__
#define HAL_ADC_H__
#include <stdint.h>
#include "nrf.h"
#if NRF51
#define ADC_IRQ_NUM ADC_IRQn
#define ADC_BASE ((NRF_ADC_Type *)NRF_ADC_BASE)
#define HAL_ADC_Type NRF_ADC_Type
#else
#define ADC_IRQ_NUM SAADC_IRQn
#define ADC_BASE ((NRF_SAADC_Type *)NRF_SAADC_BASE)
#define HAL_ADC_Type NRF_SAADC_Type
#endif
typedef enum {
HAL_ADC_CHANNEL_2 = 2,
HAL_ADC_CHANNEL_3,
HAL_ADC_CHANNEL_4,
HAL_ADC_CHANNEL_5,
HAL_ADC_CHANNEL_6,
HAL_ADC_CHANNEL_7,
} hal_adc_channel_t;
/**
* @brief ADC Configuration Structure definition
*/
typedef struct {
hal_adc_channel_t channel;
} hal_adc_config_t;
/**
* @brief ADC handle Structure definition
*/
typedef struct __ADC_HandleTypeDef {
hal_adc_config_t config; /* ADC config parameters */
} ADC_HandleTypeDef;
uint16_t hal_adc_channel_value(hal_adc_config_t const * p_adc_conf);
uint16_t hal_adc_battery_level(void);
#endif // HAL_ADC_H__

View File

@ -1,118 +0,0 @@
/*
* This file is part of the MicroPython project, http://micropython.org/
*
* The MIT License (MIT)
*
* Copyright (c) 2017 Glenn Ruben Bakke
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "mphalport.h"
#include "hal_adc.h"
#ifdef HAL_ADCE_MODULE_ENABLED
static const uint32_t hal_adc_input_lookup_pos[] = {
SAADC_CH_PSELP_PSELP_AnalogInput0 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput1 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput2 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput3 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput4 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput5 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput6 << SAADC_CH_PSELP_PSELP_Pos,
SAADC_CH_PSELP_PSELP_AnalogInput7 << SAADC_CH_PSELP_PSELP_Pos
};
#define HAL_ADCE_PSELP_NOT_CONNECTED (SAADC_CH_PSELP_PSELP_NC << SAADC_CH_PSELP_PSELP_Pos)
#define HAL_ADCE_PSELP_VDD (SAADC_CH_PSELP_PSELP_VDD << SAADC_CH_PSELP_PSELP_Pos)
/*static const uint32_t hal_adc_input_lookup_neg[] = {
SAADC_CH_PSELN_PSELN_AnalogInput0 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput1 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput2 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput3 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput4 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput5 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput6 << SAADC_CH_PSELN_PSELN_Pos,
SAADC_CH_PSELN_PSELN_AnalogInput7 << SAADC_CH_PSELN_PSELN_Pos
};*/
#define HAL_ADCE_PSELN_NOT_CONNECTED (SAADC_CH_PSELN_PSELN_NC << SAADC_CH_PSELN_PSELN_Pos)
#define HAL_ADCE_PSELN_VDD (SAADC_CH_PSELN_PSELN_VDD << SAADC_CH_PSELN_PSELN_Pos)
uint16_t hal_adc_channel_value(hal_adc_config_t const * p_adc_conf) {
int16_t result = 0;
// configure to use VDD/4 and gain 1/4
ADC_BASE->CH[0].CONFIG = (SAADC_CH_CONFIG_GAIN_Gain1_4 << SAADC_CH_CONFIG_GAIN_Pos)
| (SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos)
| (SAADC_CH_CONFIG_REFSEL_VDD1_4 << SAADC_CH_CONFIG_REFSEL_Pos)
| (SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos)
| (SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos)
| (SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos);
// positive input
ADC_BASE->CH[0].PSELP = hal_adc_input_lookup_pos[p_adc_conf->channel]; // HAL_ADCE_PSELP_VDD;
ADC_BASE->CH[0].PSELN = HAL_ADCE_PSELN_NOT_CONNECTED;
ADC_BASE->RESOLUTION = SAADC_RESOLUTION_VAL_8bit << SAADC_RESOLUTION_VAL_Pos;
ADC_BASE->RESULT.MAXCNT = 1;
ADC_BASE->RESULT.PTR = (uint32_t)&result;
ADC_BASE->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;
ADC_BASE->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
// calibrate ADC
ADC_BASE->TASKS_CALIBRATEOFFSET = 1;
while (ADC_BASE->EVENTS_CALIBRATEDONE == 0) {
;
}
ADC_BASE->EVENTS_CALIBRATEDONE = 0;
while (ADC_BASE->STATUS == (SAADC_STATUS_STATUS_Busy << SAADC_STATUS_STATUS_Pos)) {
;
}
// start the ADC
ADC_BASE->TASKS_START = 1;
while (ADC_BASE->EVENTS_STARTED == 0) {
;
}
ADC_BASE->EVENTS_STARTED = 0;
// sample ADC
ADC_BASE->TASKS_SAMPLE = 1;
while (ADC_BASE->EVENTS_END == 0) {
;
}
ADC_BASE->EVENTS_END = 0;
ADC_BASE->TASKS_STOP = 1;
while (ADC_BASE->EVENTS_STOPPED == 0) {
;
}
ADC_BASE->EVENTS_STOPPED = 0;
return result;
}
uint16_t hal_adc_battery_level(void) {
return 0;
}
#endif // HAL_ADCE_MODULE_ENABLED