Hey all :)
My project includes an analogue measure, and in some channels, the input goes over 57000mV in certain, probably random cases.
Of course, it's not a real input because it would fry the MCU. But how can I shield my signal from these spikes, and how do I prevent them totally?
My prj.cfg:
CONFIG_LOG=y CONFIG_I2C=y CONFIG_ADC=y #I know this is only the relevant one, but in case this content is worth something. CONFIG_SFLOAT=y CONFIG_CBPRINTF_FP_SUPPORT=y CONFIG_DK_LIBRARY=y
My devicetree overlay:
/ { zephyr,user { io-channels = <&adc 0>, <&adc 1>, <&adc 2>, <&adc 3>; }; }; &adc { #address-cells = <1>; #size-cells = <0>; channel@0 { reg = <0>; zephyr,gain = "ADC_GAIN_1_6"; zephyr,reference = "ADC_REF_INTERNAL"; zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>; zephyr,input-positive = <NRF_SAADC_AIN0>; /* P0.03 */ zephyr,resolution = <12>; }; channel@1 { reg = <1>; zephyr,gain = "ADC_GAIN_1_6"; zephyr,reference = "ADC_REF_INTERNAL"; zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>; zephyr,input-positive = <NRF_SAADC_AIN1>; zephyr,resolution = <12>; zephyr,oversampling = <8>; }; channel@2 { reg = <2>; zephyr,gain = "ADC_GAIN_1_6"; zephyr,reference = "ADC_REF_INTERNAL"; zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>; zephyr,input-positive = <NRF_SAADC_AIN2>; /* P0.04 */ zephyr,resolution = <12>; zephyr,oversampling = <8>; }; channel@3 { reg = <3>; zephyr,gain = "ADC_GAIN_1_6"; zephyr,reference = "ADC_REF_INTERNAL"; zephyr,vref-mv = <750>; zephyr,acquisition-time = <ADC_ACQ_TIME_DEFAULT>; zephyr,input-positive = <NRF_SAADC_AIN3>; /* P0.30 */ zephyr,resolution = <12>; }; };
My main code:
#include <zephyr/device.h> #include <zephyr/devicetree.h> #include <zephyr/drivers/adc.h> #include <zephyr/kernel.h> #include <zephyr/sys/util.h> #include <zephyr/logging/log.h> LOG_MODULE_REGISTER(ADC_Custom_Driver); #if !DT_NODE_EXISTS(DT_PATH(zephyr_user)) || \ !DT_NODE_HAS_PROP(DT_PATH(zephyr_user), io_channels) #error "No suitable devicetree overlay specified" #endif #define DT_SPEC_AND_COMMA(node_id, prop, idx) \ ADC_DT_SPEC_GET_BY_IDX(node_id, idx), /* Data of ADC io-channels specified in devicetree. */ static const struct adc_dt_spec adc_channels[] = { DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA) }; uint16_t buf; struct adc_sequence sequence = { .buffer = &buf, /* buffer size in bytes, not number of samples */ .buffer_size = sizeof(buf), }; void adc_custom_channels_setup(void) { int err; /* Configure channels individually prior to sampling. */ for (int i = 0U; i < ARRAY_SIZE(adc_channels); i++) { if (!device_is_ready(adc_channels[i].dev)) { LOG_WRN("ADC controller device not ready\n"); return; } err = adc_channel_setup_dt(&adc_channels[i]); if (err < 0) { LOG_ERR("Could not setup channel #%d (%d)\n", i, err); return; } } } int adc_custom_measure_channel(uint8_t idx) { int err; uint16_t value; (void)adc_sequence_init_dt(&adc_channels[idx], &sequence); err = adc_read(adc_channels[idx].dev, &sequence); if (err < 0) { LOG_ERR("Could not read (%d)\n", err); } else { //LOG_INF("%"PRId16, buf); value = (uint16_t)buf; LOG_DBG("Values.channels[%d] = %d\n", idx, value); return value; } } int adc_custom_measure_channel_mv(uint8_t idx) { int err; int32_t val_mv; (void)adc_sequence_init_dt(&adc_channels[idx], &sequence); err = adc_read(adc_channels[idx].dev, &sequence); /* conversion to mV may not be supported, skip if not */ val_mv = buf; err = adc_raw_to_millivolts_dt(&adc_channels[idx], &val_mv); if (err < 0 || val_mv > 5000) { LOG_ERR(" (value in mV not available)\n"); } else { LOG_DBG("Values_mv[%d] = %d mV\n",idx, val_mv); return val_mv; } }
I call the setup once and in a loop for the measure / measure_print methods.
Is this bug possible because I configured the functions as int and not uint16?
I'm using nRF52840 / Thingy52 (with proper overlays, of course) and NCS v2.2.0