一颗=3颗(nPM1300电源芯片)

2024-08-21 13:40:53 浏览数 (2)

nPM1300是NRF最新的电源IC,文章比较长,请耐心观看:

对比以前的芯片来看,这次是补全了前面芯片的空缺,而且DCDC LDO 充电这样的设置可以让嵌入式设备的体积再变小一些:

就像一个项目的电源系统,里面有数字的MCU,也有模拟的AEF,以及为了便携的充电芯片,现在一颗芯片就可以全搞定了,而且还多了很多高级功能,比如可调的LDO和BUCK,以及高端产品才能拥有的运输模式。

下面的一个框图就说明了在设计上面的优势,可以直接通过USB接口充电,还拥有最新的Type-C标准,为了充电的上面的安全还加入了NTC功能配合恒流恒压等可以让设备更加的安全,其实配套软件还有更多的功能,可以预测什么的,看别人评测吧。

可以通过外置电阻的设置,在芯片没有被主机控制的情况下就可以供电。最后我觉得是官方给的BUCK做LDO给MCU供电还挺好,剩下的两个LDO做模拟和数字电源。

其实还有一路主机供电的电源,也可以作为扩展电源出现。

1.可以有两个LDO,一个模拟域,一个数字域(但是我没有找到纹波)

2.两个BUCK,有两个模式

1PWM 和滞后模式可根据负载自动切换

1滞后模式可在较低负载电流下提供效率,并且通常以最大 PWM 电流的一半运行。

1BUCK 默认在自动模式下运行。在自动模式下,BUCK 针对低负载电流选择滞后模式,针对高负载电流选择 PWM 模式。

1在 PWM 模式下,BUCK 由于恒定的开关频率和较低的电压纹波而提供清洁的电源,从而与 RF 电路实现最佳共存。

1VSET1和VSET2引脚仅在通电时启用。如果存在 电阻 R (VSETn ,则 BUCK 启用,输出电压由电阻值)定义。如果引脚接地,则 BUCK 禁用。

有两个电阻是控制BUCK输出的

BUCK 的输出电压范围可通过 TWI (IIC) 进行编程。默认输出电压选择位于引脚VSET1VSET2上,这些引脚使用外部电阻器配置为GND

BUCK 1和2 的设置电阻

输出电压范围为 1.0 V 至 3.3 V,步长为 100 mV,并在电压配置寄存器BUCK1NORMVOUT和BUCK2NORMVOUT中设置。一旦选择了电压,必须写入寄存器BUCKSWCTRLSEL才能使值生效。

寄存器BUCK1VOUTSTATUS和BUCK2VOUTSTATUS 指示状态或当前电压设置。

这个是编程时候的要点

BUCK组件需要电感和电容

官方的板子推荐的是这颗,但是jlc没有现货,需要在贸泽上面定欧

这个有个重要的参数是要启用BUCK输出的最小VSYS电压,是2.7V,最大的降压电流是0.2A。然后两个电源纹波

强制BUCK1 进入PWM模式

正常模式的输出电压

状态寄存器,BUCK有些寄存器我看不懂是做什么的

可以精确的按照0.1V的步进来调整

充电的电流是可以限制的,USB上面的

VBUS上面的电压信息是可以输出的,所以这里也可以做USB接口信息检测

涓流就是以低速率且恒定方式对电池提供很小的充电电流。

恒流,就是充电电流保持不变,不管输出电压如何变化,锂电池的主要充电方式,电流大于500mA。

电池维护功能

充电电流限值以 2 mA 为步长设置在 32 mA 至 800 mA 之间。充电电流 I (CHG)由 TWI 配置,默认值为 32 mA。

支持NTC测温

可以通过NTC 电流的配合来适应温度智能充电

电池的充电终止电压也是可以设置的,常温下

涓流充电设置,默认是2.9V

充电状态,这些都是可以通过查询来读出的

官方的板子真的很漂亮,hhhh,原理图也是赏心悦目

LED-DRV 由三个相同的低侧 LED 驱动器组成,位于引脚 LED0LED1LED2上。引脚配置彼此独立。

可以在寄存器中配置引脚以实现以下目的:

1充电指示

1充电错误指示

1RGB LED(需要全部三个引脚)

1通用开漏输出

开漏模式一般应用在I2C、SMBUS通讯等需要“线与”功能的总线电路中,除此之外,还用在电平不匹配的场合,如需要输出5伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5伏,并且把GPIO设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5伏的电平。

所以:在开漏模式下运行的每个 LED 引脚都需要一个外部上拉电阻。

GPIO 由VDDIO引脚供电。

GPIO作为输入的时候,一定有去抖动,这里直接内置了,20ms,实在是贴心,给出了一个寄存器来控制

给了一个定时器,但是是一带而过。

但是我研究后,不知道这个东西咋用:

当设备处于休眠模式时,唤醒定时器会以可编程间隔唤醒系统。当系统处于运输或休眠模式时,请勿使用看门狗定时器或通用定时器。

运输和休眠模式将电池与系统隔离,并最大限度地减少静态电流。

休眠模式与运输模式相同,不同之处在于,在休眠模式下,计时器正在运行并作为额外的唤醒源。

这个运输模式,现在在产品上面还挺普遍的,比如无人机,电脑,电动牙刷什么的。

Ship功能是在产品出厂之后的长期保管中,尽可能减少电池余量的功能。Ship功能也称为运输模式等其它名称。

没有搭载Ship功能的电子设备,出厂后仍处于电池发生消耗电流的状态。在这种状态下,电子设备在长期保存中电池余量逐渐减少,导致的电池因深度过放电导致的损坏。

可以设想当产品到达最终客户时,可能会出现电池电量太低以至产品不能立即启动,或者目标电池驱动时间不足的情况。

为了抑制出厂后长期保存状态下电池发生的电流消耗,电子设备需要具备Ship功能。

就是一种

有三种方式退出这个模式,按键,当你摁对应的按钮够了时间就退出,还有VSYS电压唤醒,以及定时器自动唤醒

真不好翻译,应该就是测量一个按键上面的时间。

SHPHLD引脚除了用于退出航行和休眠模式外,还是一个复位控制

芯片操作其实简单的,就是IIC:

TWI 由 VDDIO 供电。建议将VDDIO连接到 BUCK 输出、VOUT1VOUT2。除运输和休眠模式外,芯片的所有操作模式下都必须有 VDDIO。

也就是推荐连接到BUCK上面

设计的时候,这个VDDIO

夸夸大厂的文档,IIC协议写的简洁明了,开始信号 地址 读写 回应 寄存器地址 8位数据 回复 不要啦

对应的读取

看一个官方给的demo,里面要点众多,幸亏我用了一次。这里分析一下:Type-C的CC感应线,还有USB -上面的保护二极管:

注意这里的USB需要差分走线,电池输入部分使用了NTC测温,重启的引脚被引出,LED也是被引出,BUCK的输出电压被外置的电阻指定,运输引脚被引出,IIC控制引出,还有中断和重启,就是软件自动控制,不需要手动,VDDIO是1.8V,记住我上面写的东西,这个地方是芯片的供电,推荐是BUCK1上面,LDO的输出有两个滤波电容。

这里就有个有趣的事情,我们都知道MCU需要一个LDO,但是我用了PMIC,PMIC是数字器件,必须主机启动后使用IIC控制,这里就有一些鸡生蛋蛋生鸡的问题,所以需要PMIC在MCU启动前就给MCU供电。

SO:BUCK1 自动启动并为 nRF5x 主机 SoC 提供 1.8 V 电压。

BUCK1 是系统的 I/O 电压。

BUCK2 自动启动,提供 3 V 输出电压,用于其他应用功能。

这里也学了新东西,BUCK可以直接给MCU供电,PMIC是可以的。

在以上VBUS是USB的电压:

PMIC上面还天然的设计了一个VBUSOUT的引脚,时候应用USB外设的器件

我在PCB设计之前,喜欢研究芯片的引脚,因为布过线的都知道,一个良好的布局多重要,芯片的左边是BUCK,下面是IIC,左面是LDO,上面是USB部分,大概就是这样的。

官方给了三个配置

注意的地方就是电源这些,IIC的上拉:

我这里给出自己的设计图,LDO的输出我留了俩路,可以给模拟和数字器件分别供电,中间给出了BUCK的设置电压用的电阻表。

这里学习官方,上拉和设置使用了最小的封装

在简单的配置里面,最小封装是用在了滤波和上下拉。

最简单同理

布局要求是:

为了获得最佳性能,建议使用至少两层的 PCB,其中包括接地层。(这里都是4层的,因为性能是一部分,布线我实在是器件多了2层布不出来,一个完整层被打的七零八落的,哭死)

BUCK 电源电压应使用尽可能靠近电源引脚的高性能电容器进行去耦。

应避免在 PCB 上采用较长的电源线。所有设备接地、VDD 连接和 VDD 旁路电容都必须尽可能靠近设备连接。

官方的PCB里面给的布局,其实就是真实PCB的一个改版,主要是去耦电容更加的紧凑,主要是左边BUCK的电容和电感。

就是布这里的时候要求足够的近,一个小环路

这里是可以从电容中间之间穿线出去

在PCB里面更加的清晰,对称布局

看我画住的地方

这个布局就很好,真实布局

我自己的布局就不好,过多的孔打散了地,以及追求对称失去了性能,需要整改

比如LDO的偏置电容,一般是要求直接压在上面的

现在在看一次这个布局,就很清晰了

在软件开发上面,也是齐全的配置,首先使用官方最大支持力度的zephyr,demo的代码也是基于此:

可以GitHub上面搜索这个库

这次设计给到了:提供了一个 shell 接口来支持 nPM1300 PMIC 的功能,我更改为串口控制版:

官方指令

实现的独有函数,还有一个回调,但是耦合很强,就没有分析了,就看单函数

分析一个吧,是读取多个寄存器的函数,说实话套的很深:

因为寄存器是基地址 偏移,前者是高八位,后是第八位,其实这个是说明了要读取的寄存器位置

这个内联函数封装了I2C通信,通过 i2c_write_read 函数执行具体的读写操作。参数包括I2C设备规范、写缓冲区、写字节数、读缓冲区和读字节数。

然后内联函数才又执行了一个函数

函数通过I2C接口执行写和读操作。它构建了两个I2C消息,一个用于写操作,另一个用于读操作。然后调用 i2c_transfer 函数执行这两个消息。

1msg[0]: 写操作,包含要写入的数据。

1msg[1]: 读操作,包含要读取的数据。

1I2C_MSG_RESTART | I2C_MSG_READ | I2C_MSG_STOP 标志表示在读操作之前发送重启信号,读操作之后发送停止信号。

mfd_npm1300_reg_read_burst 函数被调用时,会构建一个包含寄存器基地址和偏移地址的缓冲区 buff。

然后调用 i2c_write_read_dt 函数,该函数进一步调用 i2c_write_read 函数。

i2c_write_read 函数创建两个I2C消息,一个用于写入寄存器地址,另一个用于读取数据。

最终,i2c_transfer 函数执行I2C传输,写入地址后读取数据,并将数据存储在 data 缓冲区中。

我这里给出使用串口控制PMIC的代码:

C #include#include#include#include#include#include#include#include #define UART_DEVICE_NODE DT_LABEL(DT_CHOSEN(zephyr_console)) #define BUFFER_SIZE 64 static const struct device *uart_dev = DEVICE_DT_GET(UART_DEVICE_NODE); static const struct device *regulators = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_regulators)); static const struct device *charger = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_charger)); static char rx_buf[BUFFER_SIZE]; static volatile int rx_buf_pos; void uart_cb(const struct device *dev, struct uart_event *evt, void *user_data) { switch (evt->type) { case UART_RX_RDY: for (int i = 0; i < evt->data.rx.len; i ) { rx_buf[rx_buf_pos ] = evt->data.rx.buf[i]; if (rx_buf_pos >= BUFFER_SIZE) { rx_buf_pos = 0; } } break; case UART_RX_DISABLED: uart_rx_enable(dev, rx_buf, sizeof(rx_buf), 50); break; default: break; } } void configure_uart(void) { uart_callback_set(uart_dev, uart_cb, NULL); uart_rx_enable(uart_dev, rx_buf, sizeof(rx_buf), 50); } void process_command(const char *cmd) { if (strncmp(cmd, "GET_STATUS", 10) == 0) { struct sensor_value volt, current, temp, status, error; sensor_sample_fetch(charger); sensor_channel_get(charger, SENSOR_CHAN_GAUGE_VOLTAGE, &volt); sensor_channel_get(charger, SENSOR_CHAN_GAUGE_AVG_CURRENT, ¤t); sensor_channel_get(charger, SENSOR_CHAN_GAUGE_TEMP, &temp); sensor_channel_get(charger, SENSOR_CHAN_NPM1300_CHARGER_STATUS, &status); sensor_channel_get(charger, SENSOR_CHAN_NPM1300_CHARGER_ERROR, &error); printk("V: %d.d I: %d.d T: %d.d Status: %d Error: %dn", volt.val1, volt.val2, current.val1, current.val2, temp.val1, temp.val2, status.val1, error.val1); } else if (strncmp(cmd, "SET_DVS ", 8) == 0) { int state = cmd[8] - '0'; if (state >= 0 && state <= 3) { regulator_parent_dvs_state_set(regulators, state); printk("Set DVS state to %dn", state); } else { printk("Invalid DVS staten"); } } else { printk("Unknown commandn"); } } void main(void) { if (!device_is_ready(uart_dev)) { printk("UART device not readyn"); return; } if (!device_is_ready(regulators)) { printk("Regulator device not readyn"); return; } if (!device_is_ready(charger)) { printk("Charger device not readyn"); return; } configure_uart(); printk("UART initializedn"); while (1) { if (rx_buf_pos > 0) { rx_buf[rx_buf_pos] = ''; process_command(rx_buf); rx_buf_pos = 0; } k_sleep(K_MSEC(100)); } }

逻辑是:

UART初始化: configure_uart 函数设置UART回调函数,并启用接收。

接收指令: uart_cb 回调函数将接收到的数据存储在缓冲区 rx_buf 中。

处理指令: process_command 函数根据接收到的指令执行相应的操作,例如获取PMIC状态

主循环: 在 main 函数的主循环中,检查缓冲区中是否有新的指令,并调用 process_command 进行处理。

这个测量设备之后会开源

RTOS的方法可能不是所有人都用的,也贴心的给出了耦合不强的纯C:

还单独的给出了zephyr的一个库,方便开发

我最后分析一个C库LDO的操作,为了后面给移植的朋友看:

这个驱动是对芯片的功能的封装

ADK里面是寄存器最底层的封装

里面都是这种封装:

MAIN_TASKSWRESET 宏定义

1TASKSWRESET: 控制寄存器中的位,用于触发系统的完全重启。

1TASKSWRESET_NOEFFECT: 表示该位为 0 时不产生任何效果。

1TASKSWRESET_TRIGGER: 当写入该位为 1 时,会触发任务,执行完全重启操作。

(0UL)

1这个表达式表示一个无符号长整型常量,其值为 0。

(0x1UL << MAIN_TASKSWRESET_TASKSWRESET_Pos)

10x1UL 是一个无符号长整型常量,其十六进制表示为 0x1,即二进制 0001。

1<< 是左移位操作符,用于将 0x1 左移 MAIN_TASKSWRESET_TASKSWRESET_Pos 位。

1MAIN_TASKSWRESET_TASKSWRESET_Pos 是宏定义中的位偏移量,它指示了在寄存器中要操作的位的位置。

例如,假设 MAIN_TASKSWRESET_TASKSWRESET_Pos 的值为 0,那么这个表达式将会计算为 0x1 << 0,结果为 0x1,即二进制 0001。这意味着这个宏定义生成了一个掩码,可以用来设置或清除特定寄存器中的位。

移植的时候,只要满足:

这两个函数就可以了。

代码语言:javascript复制
https://github.com/NordicSemiconductor/npmx-zephyr
代码语言:javascript复制
https://github.com/zephyrproject-rtos/zephyr/blob/main//samples/shields/npm1300_ek/doc/index.rst#id2
代码语言:javascript复制
https://nordicsemiconductor.github.io/npmx/drivers/adc/index.html
代码语言:javascript复制
https://docs.nordicsemi.com/bundle/ps_npm1300/page/chapters/ordering_info/doc/ordering_info.html
代码语言:javascript复制
https://infocenter.nordicsemi.com/pdf/nRF52840_PS_v1.7.pdf
代码语言:javascript复制
https://www.nordicsemi.com/Products/nRF52840
代码语言:javascript复制
https://product.torex.com.cn/cn/technical-support/techfaq/doc_4262
代码语言:javascript复制
https://www.ti.com.cn/product/cn/MSPM0L1106?bm-verify=AAQAAAAJ_____94NfixNSc5gIZiom7vfqTlren0d_BxDX5T7ru2uqX2Oe9fynoDdF_Gax9xpW2SCpUSZaN3tCvlg_GkMLX8G3B7aJm1aHjLopBBDd7bsXOGAaOEyIJ7s3D3YVoSVmq8_uxM7X1AL0DCyqgSlw-HQJ40bcWiubEAvU1viLNvd_C4nrZa03jX8N6NDeOUh8NpF-RDu7uydQDSW70OCbGKWbKw5fU92YYJkPSYIL2tr59YJyGWasdyg-couassLwjI4UUxiIvjc45nj-Zw8dp28zfYAvYFELRji_M767hum8b35dVq1ICjoKst_ZAFM_d6vcK-8i6bG1xuEaUjUXZo

0 人点赞