LENDO ENTRADAS ANALÓGICAS NO NINA B112 COM SEGGER STUDIO, JAVASCRIPT, M-BED, ARDUINO, PYTHON e o NINA W102 com ARDUINO e ESP-IDF
O objetivo deste BLOG é mostrar como ler entradas analógicas do NINA B112 e NINA W102 com diferentes linguagens de programação.
Nos BLOGS anteriores foi visto como instalar o SEGGER STUDIO, JAVASCRIPT, M-BED, ARDUINO E PYTHON para o NINA B112 bem como ARDUINO e PLATFORMIO para NINA W102.
Foram utilizados os EVK-NINA-B1 e EVK-NINA-W1 para testes.
NINA B112
1) CÓDIGO NO SEGGER STUDIO
Dicas: no sdk_config.h, esta para 10 bits a resolução. Habilite tambe nrf_log_rtt.
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#define SAMPLES_IN_BUFFER 5
volatile uint8_t state = 1;
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t m_ppi_channel;
static uint32_t m_adc_evt_counter;
void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
APP_ERROR_CHECK(err_code);
/* setup m_timer for compare event every 400ms */
uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
nrf_drv_timer_extended_compare(&m_timer,
NRF_TIMER_CC_CHANNEL0,
ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
false);
nrf_drv_timer_enable(&m_timer);
uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
NRF_TIMER_CC_CHANNEL0);
uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();
/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
timer_compare_event_addr,
saadc_sample_task_addr);
APP_ERROR_CHECK(err_code);
}
void saadc_sampling_event_enable(void)
{
ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
APP_ERROR_CHECK(err_code);
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
for (i = 0; i < SAMPLES_IN_BUFFER; i++)
{
NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
}
m_adc_evt_counter++;
}
}
void saadc_init(void)
{
ret_code_t err_code;
nrf_saadc_channel_config_t channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
/**
* @brief Function for main application entry.
*/
int main(void)
{
uint32_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
ret_code_t ret_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(ret_code);
saadc_init();
saadc_sampling_event_init();
saadc_sampling_event_enable();
NRF_LOG_INFO("SAADC HAL simple example started.");
while (1)
{
nrf_pwr_mgmt_run();
NRF_LOG_FLUSH();
}
}
/** @} */
2) CÓDIGO NO ARDUINO
int adcin = A0;
int adcvalue = 0;
void setup() {
analogReference(AR_INTERNAL);
analogReadResolution(10);
Serial.begin(115200);
}
void loop() {
// Get a fresh ADC value
adcvalue = analogRead(adcin);
// Display the results
Serial.println(adcvalue);
delay(1000);
}
3) CÓDIGO NO ARDUINO (AVANÇADO)
// Will Langford
// Jan 12, 2018
// Basic example showing how to use the SAADC with oversampling and interrupts
// In this code we:
// set up the SAADC to oversample 256x in a single-ended configuration on Analog 0 (Pin 0.2)
// enable burst mode so that we only need to trigger 1 sample to get a fully sampled (256x) result
// enable an interrupt on the SAADC END_EVENT which triggers whenever the result buffer is full
static int16_t data_buffer[1];
volatile bool saadc_results_ready = false;
extern "C" // for some strange reason this seems necessary for the interrupt to function
{
void SAADC_IRQHandler(void)
{
// Clear events
NRF_SAADC->EVENTS_END = 0;
saadc_results_ready = true;
}
}
void adc_setup() {
NVIC_EnableIRQ(SAADC_IRQn);
NVIC_ClearPendingIRQ(SAADC_IRQn);
//configure SAADC resolution
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
// enable oversampling
NRF_SAADC->OVERSAMPLE = (SAADC_OVERSAMPLE_OVERSAMPLE_Over256x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos) & SAADC_OVERSAMPLE_OVERSAMPLE_Msk ;
//enable SAADC
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//set result pointer
NRF_SAADC->RESULT.PTR = (uint32_t)(&data_buffer);
NRF_SAADC->RESULT.MAXCNT = 1; // number of samples
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;
}
//set channel 0 resistor network, gain, reference, sample time, and mode
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_5 << 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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk)
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
//configure Channel 0 to use A0 as positive
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_AnalogInput0;
// Enable SAADC END interrupt to do maintainance and printing of values.
NRF_SAADC->INTENSET = SAADC_INTENSET_END_Enabled << SAADC_INTENSET_END_Pos;
NVIC_EnableIRQ(SAADC_IRQn);
}
void adc_start()
{
// Enable SAADC. This should be done after the SAADC is configure due to errata 74 SAADC: Started events fires prematurely
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//start task
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
}
void setup() {
Serial.begin(9600);
Serial.println("started...");
adc_setup();
adc_start();
Serial.println("adc started...");
}
void loop() {
if (saadc_results_ready) {
Serial.println(data_buffer[0]);
// restart acquistion
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED); NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
saadc_results_ready = false;
}
delay(1000);
}
4) CÓDIGO NO M-BED (testado com Platformio)
#include "mbed.h"
#include "stdio.h"
static int16_t data_buffer[1];
volatile bool saadc_results_ready = false;
AnalogIn ain(A0);
int main() {
//configure SAADC resolution
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
// enable oversampling
NRF_SAADC->OVERSAMPLE = (SAADC_OVERSAMPLE_OVERSAMPLE_Over256x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos) & SAADC_OVERSAMPLE_OVERSAMPLE_Msk;
//enable SAADC
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//set result pointer
NRF_SAADC->RESULT.PTR = (uint32_t)(&data_buffer);
NRF_SAADC->RESULT.MAXCNT = 1; // number of samples
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;
}
//set channel 0 resistor network, gain, reference, sample time, and mode
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_5 << 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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk)
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
//configure Channel 0 to use A0 as positive
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_AnalogInput0;
// Enable SAADC. This should be done after the SAADC is configure due to errata 74 SAADC: Started events fires prematurely
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//start task
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
while(1)
{
printf("%d\r\n",data_buffer[0]);
fflush(stdout);
// restart acquistion
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
wait(0.5);
}
}
5) CÓDIGO NO JAVASCRIPT
var ll = require("NRF52LL");
var on = false;
var saadc = ll.saadc({
resolution : 10,
channels : [ { // channel 0
pin:D29,
gain:1/4,
tacq:40,
refvdd:false,
} ]
});
setInterval(function() {
on = !on;
LED1.write(on);
print(saadc.sample()[0]);
}, 250);
6) CÓDIGO NO PYTHON (default 10 bits, internal REF. Analogin sempre gera valor de 16 bits)
import time
import board
from analogio import AnalogIn
analogin = AnalogIn(board.A0)
while True:
print(analogin.value)
time.sleep(1.0)
NINA B112
1) CÓDIGO NO ARDUINO
int val;
const uint8_t ANALOG_PIN = A0;
void setup() {
Serial.begin(19200);
}
void loop() {
val = analogRead(ANALOG_PIN); //12 BITS
Serial.println(val);
delay(1000);
}
2) CÓDIGO NO ESP-IDF
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64 //Multisampling
static esp_adc_cal_characteristics_t *adc_chars;
static const adc_channel_t channel = ADC_CHANNEL_6; //GPIO34 if ADC1, GPIO14 if ADC2
static const adc_atten_t atten = ADC_ATTEN_DB_0;
static const adc_unit_t unit = ADC_UNIT_1;
static void check_efuse()
{
//Check TP is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
printf("eFuse Two Point: Supported\n");
} else {
printf("eFuse Two Point: NOT supported\n");
}
//Check Vref is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
printf("eFuse Vref: Supported\n");
} else {
printf("eFuse Vref: NOT supported\n");
}
}
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
printf("Characterized using Two Point Value\n");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
printf("Characterized using eFuse Vref\n");
} else {
printf("Characterized using Default Vref\n");
}
}
void app_main()
{
//Check if Two Point or Vref are burned into eFuse
check_efuse();
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(channel, atten);
//Characterize ADC
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
//Continuously sample ADC1
while (1) {
uint32_t adc_reading = 0;
//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++)
adc_reading += adc1_get_raw((adc1_channel_t)channel);
adc_reading /= NO_OF_SAMPLES;
printf("%d\n", adc_reading);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
Referências
https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-analog-in
https://u-blox-ninab112-circuitpython.blogspot.com/2018/10/u-blox-nina-b112-javascript-o-objetivo.html
https://www.segger.com/
http://www.espruino.com/NRF52LL
https://os.mbed.com/handbook/AnalogIn
https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/nrf52-adc
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html#overview
https://mjrobot.org/2017/09/26/iot-feito-facil-brincando-com-o-esp32-no-arduino-ide/
Nos BLOGS anteriores foi visto como instalar o SEGGER STUDIO, JAVASCRIPT, M-BED, ARDUINO E PYTHON para o NINA B112 bem como ARDUINO e PLATFORMIO para NINA W102.
Foram utilizados os EVK-NINA-B1 e EVK-NINA-W1 para testes.
NINA B112
1) CÓDIGO NO SEGGER STUDIO
Dicas: no sdk_config.h, esta para 10 bits a resolução. Habilite tambe nrf_log_rtt.
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "nrf.h"
#include "nrf_drv_saadc.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "boards.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "app_util_platform.h"
#include "nrf_pwr_mgmt.h"
#include "nrf_log.h"
#include "nrf_log_ctrl.h"
#include "nrf_log_default_backends.h"
#define SAMPLES_IN_BUFFER 5
volatile uint8_t state = 1;
static const nrf_drv_timer_t m_timer = NRF_DRV_TIMER_INSTANCE(0);
static nrf_saadc_value_t m_buffer_pool[2][SAMPLES_IN_BUFFER];
static nrf_ppi_channel_t m_ppi_channel;
static uint32_t m_adc_evt_counter;
void timer_handler(nrf_timer_event_t event_type, void * p_context)
{
}
void saadc_sampling_event_init(void)
{
ret_code_t err_code;
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
timer_cfg.bit_width = NRF_TIMER_BIT_WIDTH_32;
err_code = nrf_drv_timer_init(&m_timer, &timer_cfg, timer_handler);
APP_ERROR_CHECK(err_code);
/* setup m_timer for compare event every 400ms */
uint32_t ticks = nrf_drv_timer_ms_to_ticks(&m_timer, 400);
nrf_drv_timer_extended_compare(&m_timer,
NRF_TIMER_CC_CHANNEL0,
ticks,
NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK,
false);
nrf_drv_timer_enable(&m_timer);
uint32_t timer_compare_event_addr = nrf_drv_timer_compare_event_address_get(&m_timer,
NRF_TIMER_CC_CHANNEL0);
uint32_t saadc_sample_task_addr = nrf_drv_saadc_sample_task_get();
/* setup ppi channel so that timer compare event is triggering sample task in SAADC */
err_code = nrf_drv_ppi_channel_alloc(&m_ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(m_ppi_channel,
timer_compare_event_addr,
saadc_sample_task_addr);
APP_ERROR_CHECK(err_code);
}
void saadc_sampling_event_enable(void)
{
ret_code_t err_code = nrf_drv_ppi_channel_enable(m_ppi_channel);
APP_ERROR_CHECK(err_code);
}
void saadc_callback(nrf_drv_saadc_evt_t const * p_event)
{
if (p_event->type == NRF_DRV_SAADC_EVT_DONE)
{
ret_code_t err_code;
err_code = nrf_drv_saadc_buffer_convert(p_event->data.done.p_buffer, SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
int i;
NRF_LOG_INFO("ADC event number: %d", (int)m_adc_evt_counter);
for (i = 0; i < SAMPLES_IN_BUFFER; i++)
{
NRF_LOG_INFO("%d", p_event->data.done.p_buffer[i]);
}
m_adc_evt_counter++;
}
}
void saadc_init(void)
{
ret_code_t err_code;
nrf_saadc_channel_config_t channel_config =
NRF_DRV_SAADC_DEFAULT_CHANNEL_CONFIG_SE(NRF_SAADC_INPUT_AIN0);
err_code = nrf_drv_saadc_init(NULL, saadc_callback);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_channel_init(0, &channel_config);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[0], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_saadc_buffer_convert(m_buffer_pool[1], SAMPLES_IN_BUFFER);
APP_ERROR_CHECK(err_code);
}
/**
* @brief Function for main application entry.
*/
int main(void)
{
uint32_t err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
ret_code_t ret_code = nrf_pwr_mgmt_init();
APP_ERROR_CHECK(ret_code);
saadc_init();
saadc_sampling_event_init();
saadc_sampling_event_enable();
NRF_LOG_INFO("SAADC HAL simple example started.");
while (1)
{
nrf_pwr_mgmt_run();
NRF_LOG_FLUSH();
}
}
/** @} */
int adcin = A0;
int adcvalue = 0;
void setup() {
analogReference(AR_INTERNAL);
analogReadResolution(10);
Serial.begin(115200);
}
void loop() {
// Get a fresh ADC value
adcvalue = analogRead(adcin);
// Display the results
Serial.println(adcvalue);
delay(1000);
}
3) CÓDIGO NO ARDUINO (AVANÇADO)
// Will Langford
// Jan 12, 2018
// Basic example showing how to use the SAADC with oversampling and interrupts
// In this code we:
// set up the SAADC to oversample 256x in a single-ended configuration on Analog 0 (Pin 0.2)
// enable burst mode so that we only need to trigger 1 sample to get a fully sampled (256x) result
// enable an interrupt on the SAADC END_EVENT which triggers whenever the result buffer is full
static int16_t data_buffer[1];
volatile bool saadc_results_ready = false;
extern "C" // for some strange reason this seems necessary for the interrupt to function
{
void SAADC_IRQHandler(void)
{
// Clear events
NRF_SAADC->EVENTS_END = 0;
saadc_results_ready = true;
}
}
void adc_setup() {
NVIC_EnableIRQ(SAADC_IRQn);
NVIC_ClearPendingIRQ(SAADC_IRQn);
//configure SAADC resolution
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
// enable oversampling
NRF_SAADC->OVERSAMPLE = (SAADC_OVERSAMPLE_OVERSAMPLE_Over256x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos) & SAADC_OVERSAMPLE_OVERSAMPLE_Msk ;
//enable SAADC
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//set result pointer
NRF_SAADC->RESULT.PTR = (uint32_t)(&data_buffer);
NRF_SAADC->RESULT.MAXCNT = 1; // number of samples
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;
}
//set channel 0 resistor network, gain, reference, sample time, and mode
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_5 << 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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk)
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
//configure Channel 0 to use A0 as positive
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_AnalogInput0;
// Enable SAADC END interrupt to do maintainance and printing of values.
NRF_SAADC->INTENSET = SAADC_INTENSET_END_Enabled << SAADC_INTENSET_END_Pos;
NVIC_EnableIRQ(SAADC_IRQn);
}
void adc_start()
{
// Enable SAADC. This should be done after the SAADC is configure due to errata 74 SAADC: Started events fires prematurely
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//start task
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
}
void setup() {
Serial.begin(9600);
Serial.println("started...");
adc_setup();
adc_start();
Serial.println("adc started...");
}
void loop() {
if (saadc_results_ready) {
Serial.println(data_buffer[0]);
// restart acquistion
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED); NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
saadc_results_ready = false;
}
delay(1000);
}
4) CÓDIGO NO M-BED (testado com Platformio)
#include "mbed.h"
#include "stdio.h"
static int16_t data_buffer[1];
volatile bool saadc_results_ready = false;
AnalogIn ain(A0);
int main() {
//configure SAADC resolution
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_10bit;
// enable oversampling
NRF_SAADC->OVERSAMPLE = (SAADC_OVERSAMPLE_OVERSAMPLE_Over256x << SAADC_OVERSAMPLE_OVERSAMPLE_Pos) & SAADC_OVERSAMPLE_OVERSAMPLE_Msk;
//enable SAADC
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//set result pointer
NRF_SAADC->RESULT.PTR = (uint32_t)(&data_buffer);
NRF_SAADC->RESULT.MAXCNT = 1; // number of samples
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;
}
//set channel 0 resistor network, gain, reference, sample time, and mode
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_5 << 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_BURST_Enabled << SAADC_CH_CONFIG_BURST_Pos) & SAADC_CH_CONFIG_BURST_Msk)
| ((SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) & SAADC_CH_CONFIG_MODE_Msk);
//configure Channel 0 to use A0 as positive
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_AnalogInput0;
NRF_SAADC->CH[0].PSELN = SAADC_CH_PSELP_PSELP_AnalogInput0;
// Enable SAADC. This should be done after the SAADC is configure due to errata 74 SAADC: Started events fires prematurely
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos);
//start task
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
while(1)
{
printf("%d\r\n",data_buffer[0]);
fflush(stdout);
// restart acquistion
NRF_SAADC->TASKS_START = 0x01UL;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0x00UL;
NRF_SAADC->TASKS_SAMPLE = 0x01UL;
wait(0.5);
}
}
5) CÓDIGO NO JAVASCRIPT
var ll = require("NRF52LL");
var on = false;
var saadc = ll.saadc({
resolution : 10,
channels : [ { // channel 0
pin:D29,
gain:1/4,
tacq:40,
refvdd:false,
} ]
});
setInterval(function() {
on = !on;
LED1.write(on);
print(saadc.sample()[0]);
}, 250);
6) CÓDIGO NO PYTHON (default 10 bits, internal REF. Analogin sempre gera valor de 16 bits)
import time
import board
from analogio import AnalogIn
analogin = AnalogIn(board.A0)
while True:
print(analogin.value)
time.sleep(1.0)
NINA B112
1) CÓDIGO NO ARDUINO
int val;
const uint8_t ANALOG_PIN = A0;
void setup() {
Serial.begin(19200);
}
void loop() {
val = analogRead(ANALOG_PIN); //12 BITS
Serial.println(val);
delay(1000);
}
2) CÓDIGO NO ESP-IDF
#include <stdio.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/adc.h"
#include "esp_adc_cal.h"
#define DEFAULT_VREF 1100 //Use adc2_vref_to_gpio() to obtain a better estimate
#define NO_OF_SAMPLES 64 //Multisampling
static esp_adc_cal_characteristics_t *adc_chars;
static const adc_channel_t channel = ADC_CHANNEL_6; //GPIO34 if ADC1, GPIO14 if ADC2
static const adc_atten_t atten = ADC_ATTEN_DB_0;
static const adc_unit_t unit = ADC_UNIT_1;
static void check_efuse()
{
//Check TP is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_TP) == ESP_OK) {
printf("eFuse Two Point: Supported\n");
} else {
printf("eFuse Two Point: NOT supported\n");
}
//Check Vref is burned into eFuse
if (esp_adc_cal_check_efuse(ESP_ADC_CAL_VAL_EFUSE_VREF) == ESP_OK) {
printf("eFuse Vref: Supported\n");
} else {
printf("eFuse Vref: NOT supported\n");
}
}
static void print_char_val_type(esp_adc_cal_value_t val_type)
{
if (val_type == ESP_ADC_CAL_VAL_EFUSE_TP) {
printf("Characterized using Two Point Value\n");
} else if (val_type == ESP_ADC_CAL_VAL_EFUSE_VREF) {
printf("Characterized using eFuse Vref\n");
} else {
printf("Characterized using Default Vref\n");
}
}
void app_main()
{
//Check if Two Point or Vref are burned into eFuse
check_efuse();
adc1_config_width(ADC_WIDTH_BIT_12);
adc1_config_channel_atten(channel, atten);
//Characterize ADC
adc_chars = calloc(1, sizeof(esp_adc_cal_characteristics_t));
esp_adc_cal_value_t val_type = esp_adc_cal_characterize(unit, atten, ADC_WIDTH_BIT_12, DEFAULT_VREF, adc_chars);
print_char_val_type(val_type);
//Continuously sample ADC1
while (1) {
uint32_t adc_reading = 0;
//Multisampling
for (int i = 0; i < NO_OF_SAMPLES; i++)
adc_reading += adc1_get_raw((adc1_channel_t)channel);
adc_reading /= NO_OF_SAMPLES;
printf("%d\n", adc_reading);
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
Questoes: suporte@smartcore.com.br
https://learn.adafruit.com/adafruit-circuit-playground-express/circuitpython-analog-in
https://u-blox-ninab112-circuitpython.blogspot.com/2018/10/u-blox-nina-b112-javascript-o-objetivo.html
https://www.segger.com/
http://www.espruino.com/NRF52LL
https://os.mbed.com/handbook/AnalogIn
https://learn.adafruit.com/bluefruit-nrf52-feather-learning-guide/nrf52-adc
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/adc.html#overview
https://mjrobot.org/2017/09/26/iot-feito-facil-brincando-com-o-esp32-no-arduino-ide/