前面几篇的试用文章我驱动了lcd屏,spi等外设,这一篇我将分享Zephyr来实现一个数字电源,用到的是EVL4248-QV-00A评估板,通过I2C与ADC来实现。
& Z0 H+ X# Q1 y1 p
# P4 Y% Z2 d: q! p3 O- S6 {0 j! d) j% ]0 {3 U3 u# n( q
一、EVL4248-QV-00A 评估板简介9 l0 W: m8 x' `* A
EVL4248-QV-00A 是 MPS 的数字电源评估板,核心是一片 MP4248GQV:四开关 Buck-Boost 变换器 + I2C(PMBus)数字接口。
7 `0 ~( G/ G4 J/ X O o9 [9 h# J1 D, \7 k
+ M* y3 F- \; e ?# Z
二、控制引脚与反馈引脚8 R2 T6 _) ^; v6 Z% ~% G
3 X7 h& o$ W7 e4 R
I2C 关键寄存器(PMBus):
1 d M, h$ f% Y# Y
8 `' I* r- R4 d) b4 h! i三、与开发板的接法
, X) o& [% r5 y3 J: k1 k: O! R
( p M9 }# J x3 c) N! \8 ^四、系统框图
* }+ _* W- Y" U) N B
' @/ Q+ G) x1 [3 [$ K6 \, ~1 h
2 K7 ~2 x+ U. V" S' z) M5 ?
功率通路:直流输入 → EVL4248(MP4248 升降压)→ 输出端子 → 负载。
. ?# Z, m' L7 o: G# |7 h3 S' A控制/反馈通路:I2C4 下发调压限流;IMON(电流)与 VOUT 分压(电压)进 ADC 实测回读;摇杆+LCD 做人机交互。3 @9 D% W9 k0 j8 i. o7 j. {
界面用 lcd_bare 裸驱动文本渲染(不用 LVGL,轻量直接),160×128 屏按行组织,按行覆盖刷新(无整屏闪烁):% x$ W D+ O# C' `6 X
+ A% J$ c1 @1 g5 P4 `& V
六、系统控制逻辑
( g2 }; L; g3 [# i
0 X" X1 `0 T. U+ l! V0 A" {" }8 T8 F5 f; x" Q
设计要点:& f; `3 l% k2 k
• 写后即读:SET/ILIM 行显示"设定值/读回值",写没生效一眼看出;
. K* o _, B- h! U• 故障锁存语义:PMBus 状态位锁存,CLEAR_FAULTS 在开输出时自动发——历史故障与当前状态分离;2 N" ]; h* J3 \* F
• CC 是调节不是故障:进恒流时芯片降压维持电流,VOUT 实测会掉,ST 记录 OC 事件,这些都如实上屏。
N! H& M! ]3 x6 g. m# [七、Zephyr 主要代码5 O+ b7 Q* r' Z$ X% ^- M6 |1 }" v
7.1 prj.conf6 c9 \+ R/ ?% W7 h2 d8 Q! p3 \
- CONFIG_GPIO=y$ @; P& |! G8 D& R+ E# z! r
- CONFIG_SPI=y0 Q; i0 G( W1 C* Y' {& a- ]# X
- CONFIG_ADC=y* t3 G( t8 w2 _& n8 z. m3 W5 o
- CONFIG_INPUT=y
. E w9 ]- J* f0 W+ _4 N - CONFIG_I2C=y
# t; e& n2 @5 ]: f- o6 B
复制代码 板级 CONFIG_FPU=y + CONFIG_FPU_SHARING=y(BSP 里已开,调压计算用浮点)。$ v9 @( v2 f4 ~# D* C0 l
7.2 设备树 overlay(boards/nucleo_h5e5zj.overlay,节选)
2 I9 W+ c3 s5 C, I4 _ a- /* MP4248:Arduino I2C(D15=SCL=PF5 / D14=SDA=PG6),从机地址 0x67 */. e u( X9 \& Y. q; J" n6 E& q
- &i2c4 {
' u7 e1 j- J" a8 y3 o - pinctrl-0 = <&i2c4_scl_pf5 &i2c4_sda_pg6>;+ }" t3 ]3 ]" U& c+ ?
- clock-frequency = <I2C_BITRATE_FAST>; /* 400kHz(MP4248 最高 1MHz) */
$ v2 K' P6 r- e- Z4 o6 \8 M - status = "okay";
6 c2 {7 l/ f1 m! g# \ - };1 ~1 w4 S3 S F3 K" e
6 J# B0 g8 T6 d0 I- /* 摇杆:adc-keys 输入驱动(电阻分压式五向摇杆,阈值实测校准) */5 ]& m- @! X- L7 M( @7 L: ~
- joystick: joystick {4 Q6 B6 @3 `" J" o$ t/ j* `% C
- compatible = "adc-keys";
8 x$ G1 D, S) y9 j$ P9 V4 [ - io-channels = <&adc1 9>;
9 J% J! F% ^) f, F/ Y" C0 T# j - sample-period-ms = <50>;
7 w' [& L& n- M8 o5 ]* j) i - keyup-threshold-mv = <3300>;
; Z( V7 D1 X& D+ f) g% M+ o0 J - key_up { press-thresholds-mv = <595>; zephyr,code = <INPUT_KEY_UP>; };
9 Q: x. q$ H2 P# r! b. m6 D - /* ... 其余方向同理 ... */
$ u+ t- b. e2 z6 ?8 K - };
9 s9 O7 f9 F' J) L( N8 j( z6 ]# U
4 m9 `) w8 k% M) J% Y+ D- /* ADC 通道:IMON=PC2(INP12)、VOUT 分压=PC3(INP13)
& ]8 S8 Q X6 |/ N2 S+ @/ b - * ⚠️ 通道号 ≥10 时子节点名必须写十六进制(unit address 按 hex 解析),6 L. s2 b9 ^, D' ~; j$ c" m
- * channel@12 会被当成 0x12=18 号!写成 channel@c 才对。 */& Y4 b* u: R, r! D5 x# Y
- &adc1 {3 j1 Q" H. t# ]1 U' ~7 ]
- pinctrl-0 = <&adc1_inp9_pb0 &adc1_inp12_pc2 &adc1_inp13_pc3>;
6 B" W1 ]3 w4 Z9 \; Y' q/ q - /* ... */
7 `( Z1 S2 O# o; b7 G5 D - channel@c { reg = <12>; /* IMON */ };
1 B9 C! e. Y) r) L - channel@d { reg = <13>; /* VOUT */ };
: f/ O. W! a: T - };
复制代码 7.3 MP4248 驱动核心(src/mp4248.c)
& C6 q, w! `+ e, }. z h( i- /* V = ceil(VOUT × 1024 × 10 / FB_RATIO),手册要求非整数向上取整 */4 l) e8 Z3 T. n8 e4 [8 O! ?
- int mp4248_set_vout(float vout_v)
@& K6 V6 j! G# v - {6 h+ s n1 O. W# a) u1 ]( Z1 q! `
- uint16_t reg = (uint16_t)ceilf(vout_v * 1024.0f * 10.0f / MP4248_FB_RATIO);
: O) H1 ^! L5 [3 z/ ? - uint8_t buf[3] = { MP4248_CMD_VOUT, (uint8_t)(reg & 0xFF), (uint8_t)(reg >> 8) };+ j4 C; [, P& F0 c
- 7 q+ r/ z: a0 m3 H5 R# e9 y( M
- return i2c_write(i2c_dev, buf, sizeof(buf), MP4248_ADDR);9 z; @3 S# @, z5 Z
- }
- `; B: E' L0 S( Q4 G; M. c( o - $ ?* g% M' M) f0 h R/ h/ k* m
- /* IOUT_OC(A) = IOUT_LIM × 0.05,读改写保留 bit7(LDC_DISABLE) */
; N; k, f1 x5 Z5 z! i% ~ - int mp4248_set_ilimit(float amps)
3 I; ^7 A, O3 R4 t. D) m - {% I" w8 }( V+ Q" x2 Z/ e2 Z5 V2 d/ X
- /* ...钳位 0.05~5.4A... */
( a" R% @# s" g, {4 n8 y - uint8_t reg = (uint8_t)(amps / 0.05f + 0.5f);
- y5 @' h+ i$ }5 Y0 m - uint8_t buf[2] = { MP4248_CMD_ILIMIT, (uint8_t)((cur & 0x80) | reg) };6 Y# E- ?* r! X! B( j: |) Q
- /* ... */
8 ~9 _! H; |$ w' f0 e - }
复制代码 7.4 实测反馈回路(src/main.c)8 L/ d/ V1 ^7 ^ \/ w7 u5 _
- /*( {: O* Q1 Q0 W. V7 g6 I, V* |
- * dps —— NUCLEO-H5E5ZJ 数字电源(M2:调压 + 限流 + 故障状态显示)1 S- d% }2 y, E' c: ]
- *
u) w) r) e. S - * 操作:摇杆左/右 = 切换编辑项(SET 电压 / ILIM 限流);上/下 = 调整
+ S( \8 D2 T1 m- J6 a# e8 W - * (电压 0.1V 步进,限流 0.1A 步进);按下 = 输出开/关。* m& F j# a2 E, X% ^
- * 显示:lcd_bare 文本(不用 LVGL)。8 O& c+ S( o7 e- v
- *
4 w; S" k! M/ _ - * 硬件:EVL4248-QV-00A(MP4248,I2C 地址 0x67)6 g2 _* c8 Q9 F6 d7 l
- * CN2 SCL → Arduino D15(PF5) CN2 SDA → Arduino D14(PG6) CN2 GND → GND
: K6 q2 q" Z. P - * 注意:评估板须先接 VIN(I2C 在 VIN+EN 都有效时才工作);
* d& |% K" n* U _& S. L( q$ m - * 上电芯片自动输出约 5V(OTP 行为,软件拦不住),负载侧请自行断电管理。4 \- d1 ~+ w, }) j4 O& W
- *5 p& A& s& `' ], k# S1 T4 s
- * SPDX-License-Identifier: Apache-2.0( G \6 U5 u2 O3 u0 \
- */; I: R0 v. S1 r
/ M3 m8 z! @0 g- #include <stdarg.h>9 N* i1 ]! m& f" P/ ]
- #include <stdio.h>
7 S' `: J" C0 \' E5 y' \7 p( ? - #include <string.h>0 T- T2 I/ W# H3 _ c: I
6 ]# O N! k {: O- #include <zephyr/kernel.h>
) K, v1 Y" q5 x - #include <zephyr/drivers/adc.h>7 o" }: Q3 j/ l! p' e2 K! ?) _5 w5 x1 \
- #include <zephyr/input/input.h># V' ~8 v! i) _( r/ e
- #include <zephyr/sys/printk.h>- f2 W* |! X- q" O+ r9 w
1 ?5 R. C+ k* L3 D4 F$ B+ c- #include "lcd_bare.h"
- A# |; {8 o$ b3 T/ T1 h - #include "mp4248.h"
" P7 B) e# Q& k, K% E) V7 i - ( U3 X9 W3 w! M$ ]2 R( m: S0 w
- static float set_volt = 5.0f; /* 目标电压(0.1V 步进) */- C" d+ h, [# b
- static float set_ilim = 5.4f; /* 目标限流(0.1A 步进,≤5.4A) */
+ F' @$ O4 J/ |& V& ]; X - static float rb_ilim; /* 限流读回值(验证写入生效) */8 _9 Y+ U/ k( o0 Y+ j7 L. }8 c8 Q
- static int edit_target; /* 0=电压 1=限流 */
& c( J# d; C2 d; s) e - static bool output_on;+ Z; j8 c4 v, ?: t4 M
- static bool mp4248_online;
: p" o) _" S$ F- g& Z" }. C - static bool ui_dirty = true;
F( k, y- F4 r/ B5 {! Z6 |* | - static uint16_t status_word;
, |: }" ~2 b1 g1 ^% l/ B! s
' I% v5 Y2 k6 E3 p# E/ w- /* 摇杆按键事件(adc-keys 驱动,输入子系统回调) */
5 N- F; R8 R5 B, y" k( J - static volatile int pending_key;
, ^7 M0 D9 y, q/ m5 t
. |2 T' C5 _! U- o- /* IMON 电流反馈:EVL4248 IMON 脚 → PC2(ADC1_INP12),IOUT = V_IMON / 0.34 */
8 ?+ g9 Z4 E4 ~' J - static const struct adc_dt_spec imon_adc =# s o* I0 w. I# y3 v$ ]( ?
- ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 0);
$ J. I5 L5 q- K* a/ X6 V - /* VOUT 分压(101.1k/5.05k)→ PC3(ADC1_INP13),VOUT = V_ADC × VOUT_DIV_RATIO */
5 Y5 _. s5 S% }$ | c+ \: L! i - #define VOUT_DIV_RATIO ((101.1f + 5.05f) / 5.05f)
: b/ y6 Z$ |$ t! k' p% C( Y - static const struct adc_dt_spec vout_adc =" \0 z: g# K5 W" t
- ADC_DT_SPEC_GET_BY_IDX(DT_PATH(zephyr_user), 1);. p; _. o4 b* C" Z" T8 u
- static float iout_amps;
6 R( c/ I& w, B' N9 B' V& C - static float vout_volts; /* VOUT 实测值 */6 o# m/ h( E5 e! ?; r8 M6 r4 O
- static int16_t imon_raw = -1; /* 调试:ADC 原始值(-1=读失败) */1 s0 a5 y' q9 a. ~& C- j$ S9 f
- $ M# ?3 s b' F$ C; ^0 M
- static void joy_cb(struct input_event *evt, void *user_data)+ o3 m4 z0 U F6 c, E! p
- {
' a! N q* o E5 r8 @ - ARG_UNUSED(user_data);
3 T# }# v1 u% G! H9 @: ?5 t& N - if (evt->value) { /* 只处理按下 */
- l! Q. i' Y4 p - pending_key = evt->code;. c7 p7 W; z) \& u! B
- }; z) ?5 l5 L% F* Q- f: C
- }: G1 O* d6 Y+ l+ J& M$ N# v0 l
- INPUT_CALLBACK_DEFINE(NULL, joy_cb, NULL);
# L) v/ u. W( e' s; B* w5 I9 ~* @* w
* q) e8 }$ l* O3 x( ~4 S. Y$ H2 [- /* 每行补空格到满宽(20 列),行内覆盖刷新,不再整屏清屏 */8 g8 U7 h/ }$ J8 f7 A4 [1 z
- /* 读一路 ADC 并转为 mV,失败返回负 errno */4 B! r7 K7 b- p. X
- static int adc_read_mv(const struct adc_dt_spec *spec, int32_t *mv_out)2 \4 |" k9 m1 f6 Q( l1 J; T# D
- {9 i$ Y/ w$ `* T! G( F6 b* _8 e
- int16_t raw;" v, O# e, g- P) q2 I8 U" @
- struct adc_sequence seq = {0};! u8 P( T9 ?, B# M1 v0 g7 j9 \# C
- int ret = adc_sequence_init_dt(spec, &seq);7 |3 n) i9 s$ e: ~2 E$ _9 k
- ; G+ M7 i- j, S4 N7 S% d0 ^ k
- if (ret != 0) {' b, w" j0 U: X5 o r! Q: s2 y
- return ret;
. y; Z; `1 R2 C$ `, W6 h; v3 X - }
8 g* S$ j0 n& [/ M - seq.buffer = &raw;9 R1 ~' _0 D! ?7 B, ~$ W. y1 m
- seq.buffer_size = sizeof(raw);
8 s" J1 y7 ]$ C - ret = adc_read_dt(spec, &seq);; c7 T5 |% H G- ~0 S% ?
- if (ret == 0) {4 ^. R0 {9 H: V; g; Z ^; _0 J" Q
- int32_t mv = raw;8 B+ c7 h7 w+ T( A9 A! X
- # F1 T+ F2 n' r2 D+ w2 q X+ Q
- ret = adc_raw_to_millivolts_dt(spec, &mv);
/ S7 p6 o7 ^+ j E ~ - if (ret == 0) {. o) C. {5 a" j
- *mv_out = mv; f& u8 |: a+ [- A- w
- }; M8 f( P1 v! ^ x
- }
W6 r& A$ K' N. C9 y6 B - return ret;
4 K$ V3 N& h+ q - }
: R {& e2 A$ q a$ r$ Y - / W3 t& y! X7 O! q
- static void ui_line(uint8_t row, uint16_t fg, const char *fmt, ...)& B, P! M V9 F5 S
- {
1 S3 E m; i0 a+ A* r2 w- A* t - char line[24];% u3 e+ g. L# x S- |2 E
- va_list ap;
4 @/ z' d8 s8 q* k& ^* ]/ d - 1 w+ X" m5 W" P; ]5 O' _
- va_start(ap, fmt);+ C! U; B' R/ n
- vsnprintf(line, sizeof(line), fmt, ap);
1 p' p: n( a; L/ F, } - va_end(ap);! O6 g& \, A3 E
- size_t n = strlen(line);$ M) v2 `- g. Y6 g; {1 v7 F3 o# n! `0 c) X
$ v6 b$ m. o) s% x+ G- while (n < 20) {
& n' r; F G# P- B" g6 ]: _/ D - line[n++] = ' ';
8 Z7 S# K" ]" w. E! i - }1 d- _$ H" w& Q9 J! n9 q8 d9 f
- line[n] = '\0';( N/ J ?( S) S1 l/ ]
- lcd_bare_text(0, row * 8, line, fg, LCD_BLACK);4 t& g) [. D6 L2 Y+ ^) G
- }
! m' `* a4 f( w7 O# Z; P- c: O - " H) ]/ A# t% ?' d# B4 l
- static void ui_redraw(void). j+ n l! ^9 J* F
- {
* k) a( B3 [ d/ R - float rb;8 `& ?/ P% T# v [( u( X6 _& r2 g
- uint16_t st = status_word;
5 _ h; I; _ B9 F& I - ( Z: n- J; n+ V! w8 S) C
- ui_line(0, LCD_WHITE, "DPS MP4248 I2C:%s", mp4248_online ? "OK" : "ERR");
2 k( G/ R7 F8 w& A - ui_line(1, LCD_BLUE, "--------------------");
+ q" ~& N9 I; Z ]0 b3 P1 v2 p& { - ' C7 y8 N7 l# m6 u2 p
- ui_line(3, LCD_YELLOW, "%cSET: %5.2f V", edit_target == 0 ? '>' : ' ',
8 d n/ k; R+ u% g+ v - (double)set_volt);
& [" p( U" G7 X' s - ui_line(5, LCD_YELLOW, "%cILIM:%4.2f/%4.2fA", edit_target == 1 ? '>' : ' ',' \, e# a1 E1 C- |/ X$ W
- (double)set_ilim, (double)rb_ilim);
( P# Q1 G* H! q: b9 p$ Z3 ?. O1 i! t - 1 x& i9 p! c2 W4 `
- if (mp4248_get_vout(&rb) == 0) {& w, l1 {: p* g
- ui_line(7, LCD_GREEN, "VCMD: %5.2f V", (double)rb);: X9 x, F G2 J6 i3 v+ r& m+ `
- } else {! F ?# w3 g( O" f* o; }
- ui_line(7, LCD_RED, "VCMD: --.-- V");: t0 ]; ]* g* z
- }& e3 p' _* R5 h
- ! U- j# }5 k+ j4 e. n% o
- ui_line(8, LCD_GREEN, "VOUT:%5.2f V", (double)vout_volts); {6 b# W$ k% q& H# A& N
- ui_line(9, LCD_GREEN, "IOUT:%5.2f A", (double)iout_amps);# K- G1 J7 r! V+ r. H! |
6 g" M Z! `3 z1 l( w: C6 j- ui_line(11, output_on ? LCD_GREEN : LCD_RED, "OUT:%s ST:%04X",
8 e1 G! q5 e& M: M V - output_on ? "ON " : "OFF", st);, w7 r- _ `; R" q1 c
- # K( H) ^! I5 I# Q# b) E, o
- ui_line(13, LCD_WHITE, "LR:item UD:adj OK:out"); c2 j" y- f3 y8 D$ U
- ui_dirty = false;
[2 t( f( M9 }' G C - }6 x% a. i& I9 m; U& A8 }; S
- F/ D; }. F9 [- int main(void)
$ w' _6 j5 N) [) D9 v- W: D - {' a# m5 s- K E0 T! {
- printk("dps: NUCLEO-H5E5ZJ digital power supply (M2)\n");; H& o. d9 [( ?; [8 n
1 y" h" R- v) W: y. Z5 |6 Y) K- p( d- if (lcd_bare_init() != 0) {& j% m% i# z: [& C
- printk("dps: lcd init failed\n");
- a$ I- j; [# Z n! [6 v - }/ F& v( W3 w# v; ^# u) c
- lcd_bare_fill(LCD_BLACK); /* 只在开机整屏清一次,之后按行覆盖刷新 */7 r7 V! V. T, p( V3 |
- if (mp4248_init() == 0) {
7 H1 P" W }2 C1 x/ F! H5 \( f - mp4248_online = (mp4248_probe() == 0);7 d7 f6 U4 i% j5 n9 j5 k$ x( u
- if (mp4248_online) {
5 e2 L, D j: I' x. D, G - mp4248_get_ilimit(&set_ilim); /* 读回芯片当前限流作为初值 */5 v) L% u/ ?4 }- t
- }
+ n V9 I7 Y% F: z- y- y4 v, a& @" T, w - }
g/ j# z0 I, F0 n1 o - printk("dps: mp4248 %s\n", mp4248_online ? "online" : "NOT FOUND");( i+ o% P- ]: I3 i) z7 h* O
$ \5 Q" m- R6 E# ?$ i! i6 v- if (adc_is_ready_dt(&imon_adc) && adc_is_ready_dt(&vout_adc)) {5 H. Y, @. @$ e; o0 y
- int rc1 = adc_channel_setup_dt(&imon_adc);
# C6 E2 s% W/ @% q, o1 v6 }, ]5 v - int rc2 = adc_channel_setup_dt(&vout_adc);7 z& F, N8 i8 c4 T- w) h/ r
- , v3 b8 Q8 `' x1 T* s) L. D
- printk("dps: adc setup imon=%d vout=%d\n", rc1, rc2);
' d% y, S. |$ f - } else {
* W( _( h, P! E9 _ - printk("dps: adc not ready\n");
! P0 r4 J! \7 [. q" I R" Y - }
! q5 @. N. F' g- H7 F; y5 Q - ; @5 V- A3 j. }9 Q' _! P- U
- uint32_t last_poll = 0;
8 V% ]5 F# K+ c+ P/ b) V# p/ y
/ [3 o3 O& K* ~, I9 N0 U- while (1) {7 }' f4 b, v3 o5 Z A4 F
- int key = pending_key;
/ d3 f( l; U, `6 N. T - $ u( q+ `- {' f S& P' v
- pending_key = 0;
! \, w. k) C% } - switch (key) {! `, R; r( F6 K7 M) W% H9 O6 I
- case INPUT_KEY_LEFT:
: T, U: K8 W" _% ?" H) h - case INPUT_KEY_RIGHT:
4 r: I1 B; c8 H7 p - edit_target ^= 1; /* 电压 <-> 限流 */1 Y' B8 q5 q; S5 M. O
- break;1 B# E/ a: B6 R9 X; h3 X: P
- case INPUT_KEY_UP:
0 H8 @. v% r, u" w" U( c - if (edit_target == 0) {
1 A8 H- }7 g2 N - set_volt += 0.1f;
1 L8 F/ w& `/ ~ L( ~ - if (set_volt > MP4248_VOUT_MAX) {7 c' }0 x1 P+ n: w& ~+ l
- set_volt = MP4248_VOUT_MAX;. w# p/ q b' V6 Y$ ^9 I8 @
- }/ h3 m. F8 c/ U' e
- if (mp4248_set_vout(set_volt) != 0) {& m. w$ N' D6 y5 p4 k, b
- mp4248_online = false;
/ N7 u& A6 e! \& X1 h - }
& s( _. e+ s% m/ U! z - } else {
9 S$ f: J4 c* E0 q7 @ - set_ilim += 0.1f;
/ e) H$ q- c; _" G7 J - if (set_ilim > 5.4f) {. ^* @# {$ m3 a
- set_ilim = 5.4f;& c( w% I3 j, e! j; S: U: b5 T" W
- }8 X4 T5 r, \+ e/ e! U# D* K
- if (mp4248_set_ilimit(set_ilim) != 0) {
- a, N9 w5 m5 f7 q$ } - mp4248_online = false;- Z; n; }. L! `9 ` G
- }
8 E9 \& _4 e3 [1 J4 G: C - }
, P/ b3 L" J/ U* n4 ^* M/ [3 } - break;: d$ h; g3 v/ O$ _) j( x1 ?; U
- case INPUT_KEY_DOWN:
- i* V& A$ f8 t: j: j( b: E: U - if (edit_target == 0) {
4 V) h2 e2 N) L( `, i5 ^5 X - set_volt -= 0.1f;# D. K7 i' e! V+ A, k
- if (set_volt < MP4248_VOUT_MIN) {
8 }" | \) b# G0 P. E5 G - set_volt = MP4248_VOUT_MIN;
( b9 d f+ M4 E2 A2 {6 H5 Z2 h0 c - }4 G7 e: b- I. E! Z3 `& h$ T
- if (mp4248_set_vout(set_volt) != 0) {: J1 _2 S, s# d# v! b' T7 _! P
- mp4248_online = false;
% \7 x, v: O& @6 X4 d8 L; f - }
1 ?7 Z: `6 |" _" j/ x- u - } else {) b: T6 h$ W1 l+ o
- set_ilim -= 0.1f;
/ j. ]. }) n7 W! K# o5 m) ]) | - if (set_ilim < 0.5f) {
& ?4 Y4 O8 S6 l: `8 p# N1 N - set_ilim = 0.5f;
7 |+ y& [9 O: B% @0 C* g9 y0 ]' l - }& U: {) @: @! ?( c. I+ g) t& L" S+ U+ |
- if (mp4248_set_ilimit(set_ilim) != 0) {
( {2 n* D/ Q- \$ A7 [4 ` - mp4248_online = false;4 Z+ I; i% Z6 b4 F9 s* p4 u
- }
0 e% n( U7 h5 L" d* p5 c - }
3 K& R. E# b, Z5 w' H - break;. t F e% C8 i3 B
- case INPUT_KEY_ENTER:# T6 W9 k- g# p; k8 ]
- output_on = !output_on;$ I" n& h0 M* p o2 J* `2 g5 x
- if (output_on) {( N: J& G/ J; p
- /* 开输出前清掉历史故障锁存(PMBus 状态位需 CLEAR_FAULTS 才复位) */& |0 t5 T" F* }& M1 p5 p* D1 y+ o
- (void)mp4248_clear_faults();! M" F/ B9 e, U, h5 j) I
- }
& W v7 ?4 r; w; m - if (mp4248_output(output_on) != 0) {
1 p7 h, v+ x& m3 P5 ~$ {& K - mp4248_online = false;
0 x6 \1 `/ W, S! G D - }
* @# f% K5 Y! |2 A) I - printk("dps: output %s\n", output_on ? "ON" : "OFF");
. a" U8 `% ~$ Y" K - break;
" ]3 a5 L4 {) ?+ c/ }9 q5 s - default:8 G/ P' _3 D& q
- break;+ ]/ ~* ~9 Z" H; x$ O+ W! M
- }: `$ {) J) }; y m+ _/ b m
- 4 _1 q* y3 Q7 T' [5 g
- if (key != 0) {& r0 ]$ u8 X& Z8 X
- ui_dirty = true;
) {" E$ P! Z/ v9 O- R: ~ - }' q4 s/ h- F& g$ ^9 G5 N# J- k
- ) }0 k. J3 E/ y1 j0 |
- /* 500ms 轮询读回电压 + 限流读回 + 状态字 + IMON + VOUT 实测 */7 y) j/ I* u( u* p/ L9 x
- if (k_uptime_get_32() - last_poll > 500) {% b6 [7 n* }% P* P+ z$ }. a5 x
- last_poll = k_uptime_get_32();
" ^% ?7 Y* j" B2 t- \4 h( c - if (!mp4248_online) {
f) j0 S* Q% v. d, p$ i# T- @6 J - /* 离线时每 2 秒重试 probe(评估板后上电/接线恢复也能上线) */
M1 J4 Y1 r) L0 o7 R( H' C - static uint32_t last_probe;
t4 _5 B. J7 X) B- L2 l1 E; e. K
3 Q! W5 Q8 O5 \& z- U7 g: D- if (k_uptime_get_32() - last_probe > 2000) {
& i0 T! R/ A W3 t4 |- y2 ` - last_probe = k_uptime_get_32();
, ]$ K9 g( h" v+ d6 P" o# F1 Y - if (mp4248_probe() == 0) {
% B4 `2 b1 d" F2 j [% r - mp4248_online = true;
! ?5 k" S* \9 o- S6 Y6 C - mp4248_get_ilimit(&set_ilim);
5 U0 F- p% s s$ [4 T8 ? - printk("dps: mp4248 back online\n");
9 K) r: Y, b- B9 e - }- `& i% @6 x. N( g- l) `# W- ^
- }
1 ^( j! b. y- O3 i - } else {
* p; j7 o* H! g" ^ - (void)mp4248_status_word(&status_word);/ X; y" j+ ~5 T8 E9 T" _
- (void)mp4248_get_ilimit(&rb_ilim);' w' e1 C% I# a4 r, r5 J/ m
- }
9 w- l9 E% C3 c( H6 U! ^2 C+ h - /* IMON:IOUT = V_IMON / 0.34(5mΩ×68V/V) */
0 |' ^7 f* C3 }) ~3 r; B; _/ y5 J - int32_t mv;
* H% {. a5 U9 N6 d: P9 t( P5 n q/ H - int rr = adc_read_mv(&imon_adc, &mv);5 s% P5 l) i! ?6 c& Y1 K
4 k* {9 m3 R7 g) N- if (rr == 0) {
( [' L3 E4 `/ K9 `4 v - imon_raw = (int16_t)(mv * 4096 / 3300);
, v% a1 a7 S3 q9 V; b, P8 E - iout_amps = (float)mv / 1000.0f / 0.34f;
, ^1 z, I# {' p% Y1 Z9 n - } else {
. M1 U$ S' m3 ]- P - imon_raw = (int16_t)rr; /* 负 errno 直接上屏 */
5 m9 y$ f7 n; {6 S1 `& a h6 ] - printk("dps: adc read err %d\n", rr);
% v' G: F! _6 ^ - }# H2 W: t8 e7 t% V) f
- /* VOUT 分压:VOUT = V_ADC × VOUT_DIV_RATIO */
! O+ G8 H2 |4 `- o% H1 Q - if (adc_read_mv(&vout_adc, &mv) == 0) {
2 M, a! F3 O4 k5 Z7 @$ s$ t" y - vout_volts = (float)mv / 1000.0f * VOUT_DIV_RATIO;
; `3 d! A) J: I8 B; e5 f - }
: B. U0 X( Z' v7 B( V" ]* h: {. G - ui_dirty = true;; @1 h+ h5 G ]4 i4 Y
- }6 @+ S) L( v) Z, H1 X
- if (ui_dirty) {6 ^9 s& E9 S7 w; Z6 t
- ui_redraw();
3 {* D0 k% n4 j; P, o" Z# b1 C - }
# M% t( ]" k! z# n( n - k_msleep(50);
0 F( R: _! h0 s1 \( Z4 s - }
* i: R; E# L9 s6 I# r- w! b/ V - return 0;
6 b+ U; ^! f( l$ i - }
; p& {! N$ @7 u' L. x+ H7 A0 \
复制代码 八、项目展示$ |# i' ~; r, `7 K& |* d1 z+ g4 U$ t! Y
3 F7 ` I- G+ |通过按键可以实时调节输出电压、电流限值等。
8 S3 W# F& q5 r
0 @$ y$ L" u' g ]3 T% q, R
5 I d1 Y+ r; S" `3 R: C; v7 `1 E# _4 I) |# O( ~
/ |. Z! y c' Z- b/ R1 L
" {3 G$ y1 L! i% I
Y& W' ^( w! q
|