Add basic ADC support
Planning on abstracting this behind hardware setup APIs, but this works for a simple demo until then
This commit is contained in:
parent
17b3f0a89f
commit
d439778949
9 changed files with 151 additions and 0 deletions
|
|
@ -9,10 +9,12 @@ target_sources(app PRIVATE
|
||||||
core/main.c
|
core/main.c
|
||||||
core/ble.c
|
core/ble.c
|
||||||
core/routine.c
|
core/routine.c
|
||||||
|
core/hardware/adc.c
|
||||||
)
|
)
|
||||||
|
|
||||||
# User routines to compile
|
# User routines to compile
|
||||||
target_sources(app PRIVATE
|
target_sources(app PRIVATE
|
||||||
routines/routine_list.c
|
routines/routine_list.c
|
||||||
routines/input_echo.c
|
routines/input_echo.c
|
||||||
|
routines/photosensor.c
|
||||||
)
|
)
|
||||||
|
|
|
||||||
19
boards/nrf52840dongle_nrf52840.overlay
Normal file
19
boards/nrf52840dongle_nrf52840.overlay
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
/ {
|
||||||
|
zephyr,user {
|
||||||
|
io-channels = <&adc 0>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&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.02 */
|
||||||
|
zephyr,resolution = <12>;
|
||||||
|
};
|
||||||
|
};
|
||||||
75
core/hardware/adc.c
Normal file
75
core/hardware/adc.c
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <zephyr/device.h>
|
||||||
|
#include <zephyr/devicetree.h>
|
||||||
|
#include <zephyr/drivers/adc.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
/** Setup code referenced from Zephyr ADC example **/
|
||||||
|
#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),
|
||||||
|
|
||||||
|
static const struct adc_dt_spec adc_channels[] = {
|
||||||
|
DT_FOREACH_PROP_ELEM(DT_PATH(zephyr_user), io_channels, DT_SPEC_AND_COMMA)
|
||||||
|
};
|
||||||
|
|
||||||
|
static int setup = 0;
|
||||||
|
|
||||||
|
int
|
||||||
|
adc_init()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < ARRAY_SIZE(adc_channels); i++) {
|
||||||
|
int err;
|
||||||
|
const struct adc_dt_spec *chan = &adc_channels[i];
|
||||||
|
|
||||||
|
if (!adc_is_ready_dt(chan)) {
|
||||||
|
return (-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = adc_channel_setup_dt(chan);
|
||||||
|
if (err) {
|
||||||
|
return (err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setup = 1;
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
adc_get_mv(int channel)
|
||||||
|
{
|
||||||
|
uint16_t val_raw;
|
||||||
|
int32_t val_mv;
|
||||||
|
struct adc_sequence seq = {
|
||||||
|
.buffer = &val_raw,
|
||||||
|
.buffer_size = sizeof(val_raw)
|
||||||
|
};
|
||||||
|
const struct adc_dt_spec *chan;
|
||||||
|
|
||||||
|
if ((channel >= ARRAY_SIZE(adc_channels)) ||
|
||||||
|
(!setup)) {
|
||||||
|
return (INT32_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
chan = &adc_channels[channel];
|
||||||
|
adc_sequence_init_dt(chan, &seq);
|
||||||
|
|
||||||
|
if (adc_read_dt(chan, &seq) < 0) {
|
||||||
|
return (INT32_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
val_mv = (int32_t)val_raw;
|
||||||
|
if (adc_raw_to_millivolts_dt(chan, &val_mv)) {
|
||||||
|
return (INT32_MIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (val_mv);
|
||||||
|
}
|
||||||
11
core/hardware/adc.h
Normal file
11
core/hardware/adc.h
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#ifndef _ADC_H_
|
||||||
|
#define _ADC_H_
|
||||||
|
|
||||||
|
#include "includes/hardware/adc.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize ADC hardware
|
||||||
|
*/
|
||||||
|
int adc_init(void);
|
||||||
|
|
||||||
|
#endif /* _ADC_H_ */
|
||||||
|
|
@ -5,10 +5,12 @@
|
||||||
|
|
||||||
#include "core/ble.h"
|
#include "core/ble.h"
|
||||||
#include "core/routine.h"
|
#include "core/routine.h"
|
||||||
|
#include "core/hardware/adc.h"
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
adc_init();
|
||||||
routine_init();
|
routine_init();
|
||||||
ble_init();
|
ble_init();
|
||||||
|
|
||||||
|
|
|
||||||
10
includes/hardware/adc.h
Normal file
10
includes/hardware/adc.h
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
#ifndef _INCLUDES_HARDWARE_ADC_H_
|
||||||
|
#define _INCLUDES_HARDWARE_ADC_H_
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the ADC value from the given channel index. See "adc-channels" in
|
||||||
|
* your board overlay file.
|
||||||
|
*/
|
||||||
|
int adc_get_mv(int channel);
|
||||||
|
|
||||||
|
#endif /* _INCLUDES_HARDWARE_ADC_H_ */
|
||||||
3
prj.conf
3
prj.conf
|
|
@ -7,4 +7,7 @@ CONFIG_BT_GATT_DYNAMIC_DB=y
|
||||||
|
|
||||||
CONFIG_HEAP_MEM_POOL_SIZE=1024
|
CONFIG_HEAP_MEM_POOL_SIZE=1024
|
||||||
|
|
||||||
|
CONFIG_ADC=y
|
||||||
|
|
||||||
CONFIG_DEBUG=y
|
CONFIG_DEBUG=y
|
||||||
|
CONFIG_DEBUG_OPTIMIZATIONS=y
|
||||||
|
|
|
||||||
27
routines/photosensor.c
Normal file
27
routines/photosensor.c
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#include "includes/ble.h"
|
||||||
|
#include "includes/routine.h"
|
||||||
|
#include "includes/hardware/adc.h"
|
||||||
|
|
||||||
|
routine_return_e
|
||||||
|
photosensor()
|
||||||
|
{
|
||||||
|
while (routine_status() == ROUTINE_STATUS_RUNNING) {
|
||||||
|
int32_t adc_mv = adc_get_mv(0);
|
||||||
|
char buf[16];
|
||||||
|
size_t print_len;
|
||||||
|
|
||||||
|
if (adc_mv == INT32_MIN) {
|
||||||
|
ble_set_telemetry_data("Reading failed", 14);
|
||||||
|
} else {
|
||||||
|
print_len = snprintk(buf, sizeof(buf), "%dmV", adc_mv);
|
||||||
|
ble_set_telemetry_data(buf, print_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
routine_delay(500);
|
||||||
|
routine_yield();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ROUTINE_RETURN_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
|
|
||||||
/** Extern all of your routines here so they can be included in the list **/
|
/** Extern all of your routines here so they can be included in the list **/
|
||||||
extern routine_return_e input_echo();
|
extern routine_return_e input_echo();
|
||||||
|
extern routine_return_e photosensor();
|
||||||
|
|
||||||
const routine_listing_t routine_list[] = {
|
const routine_listing_t routine_list[] = {
|
||||||
{ .entry = input_echo, .name = "Input Echo" },
|
{ .entry = input_echo, .name = "Input Echo" },
|
||||||
|
{ .entry = photosensor, .name = "Photosensor" },
|
||||||
{ NULL, NULL },
|
{ NULL, NULL },
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue