Skip to content

Commit

Permalink
[FL-2969] FuriHal: add ADC API (#3583)
Browse files Browse the repository at this point in the history
* Examples: remove unused context
* FuriHal: add simple ADC API
* Examples: add ADC example app
* FuriHal: add extended configuration options for ADC API
* FuriHal: add ADC clock configuration, fix calibration routine for single ended mode, new optimized parameters, documentation.
* FuriHal: add FuriHalAdcChannelTEMPSENSOR sampling time note
* FuriHal: update FuriHalAdcChannelVBAT description.
* FuriHal: use insomnia while ADC is acquired.
* Examples: cleanup example_adc a little bit
  • Loading branch information
skotopes authored Apr 17, 2024
1 parent 1a40fae commit 70f93a4
Show file tree
Hide file tree
Showing 16 changed files with 949 additions and 57 deletions.
9 changes: 9 additions & 0 deletions applications/examples/example_adc/application.fam
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
App(
appid="example_adc",
name="Example: ADC",
apptype=FlipperAppType.EXTERNAL,
entry_point="example_adc_main",
requires=["gui"],
stack_size=1 * 1024,
fap_category="Examples",
)
176 changes: 176 additions & 0 deletions applications/examples/example_adc/example_adc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
/**
* @file example_adc.c
* @brief ADC example.
*/
#include <furi.h>
#include <furi_hal.h>

#include <gui/gui.h>
#include <gui/elements.h>
#include <input/input.h>

const uint8_t font[] =
"`\2\3\2\3\4\1\2\4\5\11\0\376\6\376\7\377\1M\2\263\3\370 \6\315\364\371\6!\12\315"
"\364\201\260\35\312Q\0\42\11\315tJI\316\13\0#\14\315\264\223dP*\203R'\1$\15\315\264"
"\262A\311\266D\251l\71\0%\15\315\264\7%\61)J\42\345 \0&\14\315\264\263$\13\223\266$"
"\7\1'\10\315\364\201\60\347\10(\10\315\364\32[\313\0)\11\315\64\322b[\35\2*\12\315\264\263"
"(\222j\71\15+\11\315\364I\331\226\23\1,\10\315\364\271\205Y\10-\10\315\364\31t\26\0.\10"
"\315\364\71\346(\0/\14\315\364\221\60\13\263\60\13C\0\60\13\315\264\245Jb)E:\12\61\12\315"
"\364\201Ll\333A\0\62\12\315\264\245bV\33r\20\63\13\315\264\245Z\232D\221\216\2\64\14\315\364"
"\201LJ\242!\313v\20\65\14\315t\207$\134\223(\322Q\0\66\13\315\264\245p\252D\221\216\2\67"
"\12\315t\207\60+\326a\0\70\13\315\264\245\222T\211\42\35\5\71\13\315\264\245J\24\215\221\216\2:"
"\11\315\364i\71!G\1;\12\315\364I\71!\314B\0<\11\315\364\341\254Z\7\1=\12\315\364)"
"C<\344$\0>\11\315\364\301\264V\207\1\77\12\315\264\245Z\35\312a\0@\14\315\264\245J\242$"
"J\272\203\0A\15\315\264\245J\224\14I\224D\71\10B\13\315t\247\312T\211\222\35\5C\12\315\264"
"\245JX\212t\24D\15\315t\247J\224DI\224\354(\0E\14\315t\207$\234\302p\310A\0F"
"\12\315t\207$\234\302:\1G\14\315\264\245J\230(Q\244\243\0H\17\315t\243$J\206$J\242"
"$\312A\0I\11\315\264\267\260m\7\1J\12\315\364\221\260%\212t\24K\14\315t\243\244\244iI"
"T\7\1L\11\315t\303\216C\16\2M\17\315t\243dH\206$J\242$\312A\0N\16\315t\243"
"D\251(Q\22%Q\16\2O\15\315\264\245J\224DI\24\351(\0P\12\315t\247J\224LaN"
"Q\15\315\264\245J\224DI\42\251\61\0R\14\315t\247J\224L\225(\7\1S\13\315\264\245\222\232"
"D\221\216\2T\10\315\264\267\260;\12U\16\315t\243$J\242$J\242HG\1V\15\315t\243$"
"J\242$Jj\71\14W\17\315t\243$J\242dH\206$\312A\0X\15\315t\243$\212\64\251\22"
"\345 \0Y\13\315t\243$Jja\35\6Z\12\315t\207\60k\34r\20[\10\315\264\264\260G\31"
"\134\12\315\264\303\64L\303\64\14]\10\315t\304\276\351\0^\11\315\364\201,\311\271\1_\7\315\364y"
"\35\4`\10\315t\322\234'\0a\14\315\364IK\224$R\222\203\0b\13\315t\303p\252D\311\216"
"\2c\12\315\364IR%\335A\0d\14\315\364\221\60Z\242$\212v\20e\12\315\364I\322\220\244;"
"\10f\12\315\364\221,\333\302:\12g\14\315\364IK\224D\321\30I\0h\14\315t\303p\252DI"
"\224\203\0i\12\315\364\201\34\21k;\10j\12\315\364\201\34\21\273e\0k\13\315t\303J\244%Q"
"\35\4l\10\315\264\305n;\10m\14\315\364)CRQ\22\245\216\1n\13\315\364)%\245\224D\71"
"\10o\12\315\364IR%\212t\24p\13\315\364)S%J\246\60\4q\13\315\364IK\224D\321X"
"\1r\11\315\364)%\245\230\23s\12\315\364I\313\232\354(\0t\13\315\364\201\60\333\302\64\7\1u"
"\15\315\364)Q\22%\211\224\344 \0v\13\315\364)Q\22%\265\34\6w\13\315\364)\25%Q\272"
"\203\0x\12\315\364)Q\244Iu\20y\15\315\364)Q\22%Q\64F\22\0z\12\315\364)CV"
"\33r\20{\12\315\364\212\265\64\254&\0|\7\315\264\302~\7}\12\315t\322\260\232\205\265\14~\11"
"\315\364II;\13\0\177\6\315\364\371\6\0\0\0\4\377\377\0";

#define FONT_HEIGHT (8u)

typedef float (*ValueConverter)(FuriHalAdcHandle* handle, uint16_t value);

typedef struct {
const GpioPinRecord* pin;
float value;
ValueConverter converter;
const char* suffix;
} DataItem;

typedef struct {
size_t count;
DataItem* items;
} Data;

const GpioPinRecord item_vref = {.name = "VREF", .channel = FuriHalAdcChannelVREFINT};
const GpioPinRecord item_temp = {.name = "TEMP", .channel = FuriHalAdcChannelTEMPSENSOR};
const GpioPinRecord item_vbat = {.name = "VBAT", .channel = FuriHalAdcChannelVBAT};

static void app_draw_callback(Canvas* canvas, void* ctx) {
furi_assert(ctx);
Data* data = ctx;

canvas_set_custom_u8g2_font(canvas, font);
char buffer[64];
int32_t x = 0, y = FONT_HEIGHT;
for(size_t i = 0; i < data->count; i++) {
if(i == canvas_height(canvas) / FONT_HEIGHT) {
x = 64;
y = FONT_HEIGHT;
}

snprintf(
buffer,
sizeof(buffer),
"%4s: %4.0f%s\n",
data->items[i].pin->name,
(double)data->items[i].value,
data->items[i].suffix);
canvas_draw_str(canvas, x, y, buffer);
y += FONT_HEIGHT;
}
}

static void app_input_callback(InputEvent* input_event, void* ctx) {
furi_assert(ctx);
FuriMessageQueue* event_queue = ctx;
furi_message_queue_put(event_queue, input_event, FuriWaitForever);
}

int32_t example_adc_main(void* p) {
UNUSED(p);

// Data
Data data = {};
for(size_t i = 0; i < gpio_pins_count; i++) {
if(gpio_pins[i].channel != FuriHalAdcChannelNone) {
data.count++;
}
}
data.count += 3; // Special channels
data.items = malloc(data.count * sizeof(DataItem));
size_t item_pos = 0;
for(size_t i = 0; i < gpio_pins_count; i++) {
if(gpio_pins[i].channel != FuriHalAdcChannelNone) {
furi_hal_gpio_init(gpio_pins[i].pin, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
data.items[item_pos].pin = &gpio_pins[i];
data.items[item_pos].converter = furi_hal_adc_convert_to_voltage;
data.items[item_pos].suffix = "mV";
item_pos++;
}
}
data.items[item_pos].pin = &item_vref;
data.items[item_pos].converter = furi_hal_adc_convert_vref;
data.items[item_pos].suffix = "mV";
item_pos++;
data.items[item_pos].pin = &item_temp;
data.items[item_pos].converter = furi_hal_adc_convert_temp;
data.items[item_pos].suffix = "C";
item_pos++;
data.items[item_pos].pin = &item_vbat;
data.items[item_pos].converter = furi_hal_adc_convert_vbat;
data.items[item_pos].suffix = "mV";
item_pos++;
furi_assert(item_pos == data.count);

// Alloc message queue
FuriMessageQueue* event_queue = furi_message_queue_alloc(8, sizeof(InputEvent));

// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, app_draw_callback, &data);
view_port_input_callback_set(view_port, app_input_callback, event_queue);

// Register view port in GUI
Gui* gui = furi_record_open(RECORD_GUI);
gui_add_view_port(gui, view_port, GuiLayerFullscreen);

// Initialize ADC
FuriHalAdcHandle* adc_handle = furi_hal_adc_acquire();
furi_hal_adc_configure(adc_handle);

// Process events
InputEvent event;
bool running = true;
while(running) {
if(furi_message_queue_get(event_queue, &event, 100) == FuriStatusOk) {
if(event.type == InputTypePress && event.key == InputKeyBack) {
running = false;
}
} else {
for(size_t i = 0; i < data.count; i++) {
data.items[i].value = data.items[i].converter(
adc_handle, furi_hal_adc_read(adc_handle, data.items[i].pin->channel));
}
view_port_update(view_port);
}
}

furi_hal_adc_release(adc_handle);
view_port_enabled_set(view_port, false);
gui_remove_view_port(gui, view_port);
view_port_free(view_port);
furi_message_queue_free(event_queue);
furi_record_close(RECORD_GUI);
free(data.items);

return 0;
}
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ int32_t example_custom_font_main(void* p) {

// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, app_draw_callback, view_port);
view_port_draw_callback_set(view_port, app_draw_callback, NULL);
view_port_input_callback_set(view_port, app_input_callback, event_queue);

// Register view port in GUI
Expand Down
2 changes: 1 addition & 1 deletion applications/examples/example_images/example_images.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ int32_t example_images_main(void* p) {

// Configure view port
ViewPort* view_port = view_port_alloc();
view_port_draw_callback_set(view_port, app_draw_callback, view_port);
view_port_draw_callback_set(view_port, app_draw_callback, NULL);
view_port_input_callback_set(view_port, app_input_callback, event_queue);

// Register view port in GUI
Expand Down
13 changes: 12 additions & 1 deletion targets/f18/api_symbols.csv
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
entry,status,name,type,params
Version,+,60.8,,
Version,+,61.0,,
Header,+,applications/services/bt/bt_service/bt.h,,
Header,+,applications/services/cli/cli.h,,
Header,+,applications/services/cli/cli_vcp.h,,
Expand Down Expand Up @@ -199,6 +199,7 @@ Header,+,targets/f7/platform_specific/cxx_virtual_stub.h,,
Header,+,targets/f7/platform_specific/intrinsic_export.h,,
Header,+,targets/f7/platform_specific/math_wrapper.h,,
Header,+,targets/furi_hal_include/furi_hal.h,,
Header,+,targets/furi_hal_include/furi_hal_adc.h,,
Header,+,targets/furi_hal_include/furi_hal_bt.h,,
Header,+,targets/furi_hal_include/furi_hal_cortex.h,,
Header,+,targets/furi_hal_include/furi_hal_crypto.h,,
Expand Down Expand Up @@ -1086,6 +1087,16 @@ Function,+,furi_event_flag_get,uint32_t,FuriEventFlag*
Function,+,furi_event_flag_set,uint32_t,"FuriEventFlag*, uint32_t"
Function,+,furi_event_flag_wait,uint32_t,"FuriEventFlag*, uint32_t, uint32_t, uint32_t"
Function,+,furi_get_tick,uint32_t,
Function,+,furi_hal_adc_acquire,FuriHalAdcHandle*,
Function,+,furi_hal_adc_configure,void,FuriHalAdcHandle*
Function,+,furi_hal_adc_configure_ex,void,"FuriHalAdcHandle*, FuriHalAdcScale, FuriHalAdcClock, FuriHalAdcOversample, FuriHalAdcSamplingTime"
Function,+,furi_hal_adc_convert_temp,float,"FuriHalAdcHandle*, uint16_t"
Function,+,furi_hal_adc_convert_to_voltage,float,"FuriHalAdcHandle*, uint16_t"
Function,+,furi_hal_adc_convert_vbat,float,"FuriHalAdcHandle*, uint16_t"
Function,+,furi_hal_adc_convert_vref,float,"FuriHalAdcHandle*, uint16_t"
Function,+,furi_hal_adc_init,void,
Function,+,furi_hal_adc_read,uint16_t,"FuriHalAdcHandle*, FuriHalAdcChannel"
Function,+,furi_hal_adc_release,void,FuriHalAdcHandle*
Function,+,furi_hal_bt_change_app,FuriHalBleProfileBase*,"const FuriHalBleProfileTemplate*, FuriHalBleProfileParams, GapEventCallback, void*"
Function,+,furi_hal_bt_check_profile_type,_Bool,"FuriHalBleProfileBase*, const FuriHalBleProfileTemplate*"
Function,+,furi_hal_bt_clear_white_list,_Bool,
Expand Down
1 change: 1 addition & 0 deletions targets/f18/furi_hal/furi_hal.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ void furi_hal_deinit_early(void) {

void furi_hal_init(void) {
furi_hal_mpu_init();
furi_hal_adc_init();
furi_hal_clock_init();
furi_hal_random_init();
furi_hal_serial_control_init();
Expand Down
Loading

0 comments on commit 70f93a4

Please sign in to comment.