前言

        本文实现nPM1300读写寄存器的驱动,使用IO模拟IIC的方式。

IO模拟IIC,可以参考公众号文章《超级精简系列之三:超级精简的IO模拟IIC的C实现》https://mp.weixin.qq.com/s/ESzWWqxHpQevsWfjV0s2VQ。

为了方便测试,实现了shell命令行,可以通过命令行方便进行任意寄存器的读写测试。参考公众号文章《一个超级精简高可移植的shell命令行C实现》https://mp.weixin.qq.com/s/XLmbJn0SKoDT1aLdxHDrbg。

TWI电平

可以通过VDDIO引脚设置TWI的IO参考电压,这里使用VOUT2,3.3V,即P18的2和3短接。

155657o6ya5e19naei6nne

使用nPW PowerUP设置BULK2的输出为3.3V。

155657mlllrr8lr8v8r8ro

155657ig9ru9606ug4ku6h

三.协议

3.1地址

7位地址 110 1011.

所以加上W/R位,8位读写地址分别是0xD7和0xD6

#define NPM1300_WR_ADDR 0xD6  /**< 11010110 写地址 */

#define NPM1300_RD_ADDR 0xD7  /**< 11010111 读地址 */

3.2寄存器读写时序

速率100~1000kbps.

写寄存器

启动->

7位从地址/R/W加上 R/W=0-> ACK

16位寄存器地址(高字节在前)->ACK

读字节数据->ACK

停止

读寄存器

启动->

7位从地址/R/W加上 R/W=0-> ACK

16位寄存器地址(高字节在前)->ACK

启动->

7位从地址/R/W R/W=1-> ACK

读字节数据->ACK

停止

155659hs6nt6arnx2yqhxe

注意以上截图中R/W的描述。R/W BIT 0 TO READ REGISTER 1 TO WRITE是反的,文档是错误的,应该是0表示写,1表示读。

3.3寄存器

参考规格书的6,7,8灯章节,寄存器分布在各个章节,不是集中在一起。

寄存器的高8位即bank,参考寄存器的Base address的bit[12:8].

155659l6d51tx606zz0tp2

四.代码实现

IO模拟IIC代码,完全可移植无需任何修改

Io_iic.c

#include "io_iic.h"

/**

*                     _______________________   

*    SCL ____________|                       |__

*        ————————————————————————

*    SDA                         |______________

*        (1)      (2)        (4)         (6)

*                        (3)           (5)

*    其中(3) SDA低建立时间 (5) SDA高保持时间

*    (1) 拉高SDA  (4)拉高SDA产生上升沿

*    (2) SCL拉高 SCL高时SDA上升沿即停止信号

*/

void io_iic_start(io_iic_dev_st* dev)

{

    /* SCL高时,SDA下降沿 */

    dev->sda_write(1);               /* (1) SDA拉高以便后面产生下降沿  */

    dev->scl_write(1);               /* (2) 拉高SCL                   */

    if(dev->delay_pf != 0)           /* (3) SCL高保持*/

    {

        dev->delay_pf(dev->delayus);

    }

    dev->sda_write(0);              /* (4)SCL高时SDA下降沿 启动    */

    if(dev->delay_pf != 0)          /* (5)SCL高保持               */

    {

        dev->delay_pf(dev->delayus);

    }

    dev->scl_write(0);             /* (6)SCL恢复                 */

}

/**

*                     _______________________   

*    SCL ____________|                       |____

*                                 ————————————————

*    SDA ————————————————————————|

*        (1)      (2)        (4)         (6)

*                        (3)           (5)

*    其中(3) SDA低建立时间 (5) SDA高保持时间

*    (1) 拉低SDA  (4)拉高SDA产生上升沿

*    (2) SCL拉高 SCL高时SDA上升沿即停止信号

*/

void io_iic_stop(io_iic_dev_st* dev)

{

    /* SCL高时,SDA上升沿 */

    dev->sda_write(0);               /* (1)SDA先输出低以便产生上升沿 */

    dev->scl_write(1);               /* (2)SCL高                   */

    if(dev->delay_pf != 0)           /* (3)SCL高保持               */

    {

        dev->delay_pf(dev->delayus);

    }

    dev->sda_write(1);               /* (4)SCL高时SDA上升沿 停止    */

    if(dev->delay_pf != 0)           /* (5)SCL高保持               */

    {

        dev->delay_pf(dev->delayus);

    }

    dev->scl_write(0);               /* (6)SCL恢复                 */

}

/**

*   |       B0               | B1~B6|    B7               |           NACK/ACK      |

*                 ___________      _            __________              ____________

*    ____________|           |   x  |__________|          |____________|            |

* (1)[2]      (4)                                      (6)[7]        (9)[10]       (12)

*        (3)           (5)                                     (8)           (11)

* 其中(1)(6)(12)拉低SCL;(4)(9)拉高SCL;

* [2]输出  [7]转为读 [10]读ACK;

* (3)(8)低保持时间,(5)(11)高保持时间。

*/

int io_iic_write(io_iic_dev_st* dev, uint8_t val)

{

    uint8_t tmp = val;

    uint8_t ack = 0;

    if(dev == 0)

    {

        return -1;

    }

    if((dev->scl_write == 0) || (dev->sda_write == 0) || (dev->sda_read == 0) || (dev->sda_2read == 0))

    {

        return -1;

    }

    /* SCL下降沿后准备数据,对方上升沿采集数据,高位在前 */

    for(uint8_t i=0; i<8; i++)

    {

        dev->scl_write(0);               /* (1) SCL拉低以便修改数据    */

        if((tmp & 0x80) != 0)            /* [2] 准备SDA数据            */

        {

            dev->sda_write(1);

        }

        else

        {

            dev->sda_write(0);  

        }

        if(dev->delay_pf != 0)

        {

            dev->delay_pf(dev->delayus); /* (3) SCL拉低时间即数据建立时间 */

        }

        dev->scl_write(1);                /*(4) SCL上升沿对方采样        */

        if(dev->delay_pf != 0)

        {

            dev->delay_pf(dev->delayus); /* (5) SCL高保持时间,数据保持时间 */

        }

        tmp <<= 1;                       /* 处理下一位           */

    }

    dev->scl_write(0);                   /* (6)SCL归0  完成8个CLK */

    dev->sda_2read();                    /* [7]SDA转为读          */

    if(dev->delay_pf != 0)

    {

        dev->delay_pf(dev->delayus);     /* (8)第九个时钟拉低时间  */

    }

    dev->scl_write(1);                   /* (9)SCL上升沿          */

    ack = dev->sda_read();               /* [10]上升沿后读         */

    if(dev->delay_pf != 0)

    {

        dev->delay_pf(dev->delayus);     /* (11)第九个时钟高保持    */

    }

    dev->scl_write(0);                   /* (12)恢复SCL到低        */

    return (ack==0) ? 0 : -1;

}

/**

*   |       B0               | B1~B6|    B7               |           NACK/ACK      |

*                 ___________      _            __________              ____________

*    ____________|           |   x  |__________|          |____________|            |

* (1)[2]      (4)[5]                                    (7)[8]       (10)         (12)

*        (3)           (6)                                     (9)           (11)

* 其中(1)(7)(12)拉低SCL;(4)(10)拉高SCL;

* [2]转为读  [5]读 [8]输出ACK;

* (3)(9)低保持时间,(6)(11)高保持时间。

*/

int io_iic_read(io_iic_dev_st* dev, uint8_t* val, uint8_t ack)

{

    uint8_t tmp = 0;

    if((dev == 0) || (val == 0))

    {

        return -1;

    }

    if((dev->scl_write == 0) || (dev->sda_write == 0) || (dev->sda_read == 0) || (dev->sda_2read == 0))

    {

        return -1;

    }

    /* SCL下降沿后对方准备数据,上升沿读数据,高位在前 */

    for(uint8_t i=0; i<8; i++)

    {

        tmp <<= 1;                      /* 处理下一位,先移动后读取             */

        dev->scl_write(0);              /* (1)                               */

        dev->sda_2read();               /* [2]转为读输入高阻,以便对方能输出     */

        if(dev->delay_pf != 0)           

        {

            dev->delay_pf(dev->delayus);/* (3)SCL低保持时间                    */

        }

        dev->scl_write(1);              /* (4)SCL上升沿                        */

        if(dev->sda_read())             /* (5)读数据(SCL低时对方已经准备好数据)  */

        {

            tmp |= 0x01;                /* 高位在前,最后左移到高位              */

        }      

        if(dev->delay_pf != 0)         

        {

            dev->delay_pf(dev->delayus);/* (6)SCL高保持时间                     */

        }

    }

    dev->scl_write(0);                  /* (7)恢复SCL时钟为低                   */

    dev->sda_write(ack);                /* [8]准备ACK信号(SCL低才能更行SDL)      */

    if(dev->delay_pf != 0)

    {

        dev->delay_pf(dev->delayus);    /* (9)第九个SCL拉低时间                  */

    }

    dev->scl_write(1);                  /* (10)SCL上升沿发数据触发对方读          */

    if(dev->delay_pf != 0)

    {

        dev->delay_pf(dev->delayus);    /* (11)第九个SCL拉高保持时间              */

    }

    dev->scl_write(0);                  /* (12)第九个SCL完成恢复低                */

    //dev->sda_write(1);                /* 这里无需驱动SDA,后面可能还是读),需要发送时再驱动 */

    *val = tmp;

    return 0;

}

void io_iic_init(io_iic_dev_st* dev)

{

    if((dev != 0) && (dev->init != 0))

    {

        dev->init();

    }

}

void io_iic_deinit(io_iic_dev_st* dev)

{

    if((dev != 0) && (dev->deinit != 0))

    {

        dev->deinit();

    }

}

Io_iic.h

#ifndef IO_IIC_H

#define IO_IIC_H

#ifdef __cplusplus

    extern "C"{

#endif

#include <stdint.h>

typedef void    (*io_iic_scl_write_pf)(uint8_t val);   /**< SCL写接口     */

typedef void    (*io_iic_sda_write_pf)(uint8_t val);   /**< SDA写接口     */

typedef void    (*io_iic_sda_2read_pf)(void);          /**< SDA转为读接口 */

typedef uint8_t (*io_iic_sda_read_pf)(void);           /**< SDA读接口     */

typedef void    (*io_iic_delay_us_pf)(uint32_t delay); /**< 延时接口      */

typedef void    (*io_iic_init_pf)(void);               /**< 初始化接口     */

typedef void    (*io_iic_deinit_pf)(void);             /**< 解除初始化接口 */

/**

* \struct io_iic_dev_st

* 接口结构体

*/

typedef struct

{

    io_iic_scl_write_pf scl_write;   /**< scl写接口    */

    io_iic_sda_write_pf sda_write;   /**< sda写接口    */

    io_iic_sda_2read_pf sda_2read;   /**< sda转为读接口 */

    io_iic_sda_read_pf  sda_read;    /**< sda读接口     */

    io_iic_delay_us_pf  delay_pf;    /**< 延时接口      */

    io_iic_init_pf      init;        /**< 初始化接口    */

    io_iic_deinit_pf    deinit;      /**< 解除初始化接口 */

    uint32_t            delayus;     /**< 延迟时间      */

} io_iic_dev_st;

/**

* \fn io_iic_start

* 发送启动信号

* \param[in] dev \ref io_iic_dev_st

*/

void io_iic_start(io_iic_dev_st* dev);

/**

* \fn io_iic_stop

* 发送停止信号

* \param[in] dev \ref io_iic_dev_st

*/

void io_iic_stop(io_iic_dev_st* dev);

/**

* \fn io_iic_write

* 写一个字节

* \param[in] dev \ref io_iic_dev_st

* \param[in] val 待写入的值

* \retval 0 写成功(收到了ACK)

* \retval -2 写失败(未收到ACK)

* \retval -1 参数错误

*/

int io_iic_write(io_iic_dev_st* dev, uint8_t val);

/**

* \fn io_iic_read

* 读一个字节

* \param[in] dev \ref io_iic_dev_st

* \param[out] val 存储读到的值

* \param[in] ack 1发送NACK 0发送ACK

* \retval 0 读成功

* \retval -1 参数错误

*/

int io_iic_read(io_iic_dev_st* dev, uint8_t* val, uint8_t ack);

/**

* \fn io_iic_init

* 初始化

* \param[in] dev \ref io_iic_dev_st

*/

void io_iic_init(io_iic_dev_st* dev);

/**

* \fn io_iic_deinit

* 解除初始化

* \param[in] dev \ref io_iic_dev_st

*/

void io_iic_deinit(io_iic_dev_st* dev);

#ifdef __cplusplus

    }

#endif

#endif

Npm1300驱动代码,完全可移植无需任何修改

Npm1300.c

#include "npm1300.h"

#define NPM1300_WR_ADDR 0xD6  /**< 11010110 写地址 */

#define NPM1300_RD_ADDR 0xD7  /**< 11010111 读地址 */

/**

* \fn npm1300_read

* 读数据

* \param[in] dev \ref npm1300_dev_st

* \param[in] reg 寄存器值

* \param[out] val 存读出的值

* \retval 0  成功

* \retval <0 失败

*/

int npm1300_read(npm1300_dev_st* dev, uint16_t reg, uint8_t* val)

{

    /* 启动 */

    dev->start();

    /* 发送写地址 */

    if(0 != dev->write(NPM1300_WR_ADDR))

    {

        dev->stop();

        return -1;

    }

    /* 寄存器地址高字节 */

    if(0 != dev->write((reg>>8)&0xFF))

    {

        dev->stop();

        return -2;

    }

    /* 寄存器地址低字节 */

    if(0 != dev->write((reg>>0)&0xFF))

    {

        dev->stop();

        return -2;

    }

    /* 重新启动 */

    dev->start();

    /* 发送读地址 */

    if(0 != dev->write(NPM1300_RD_ADDR))

    {

        dev->stop();

        return -1;

    }


    /* 读数据 */

    if(0 != dev->read(val,1))

    {

        dev->stop();

        return -2;  

    }

    /* 结束 */

    dev->stop();

    return 0;

}

/**

* \fn npm1300_write

* 写数据

* \param[in] dev \ref npm1300_dev_st

* \param[in] reg 寄存器值

* \param[in] val 待写入的值

* \retval 0  成功

* \retval <0 失败

*/

int npm1300_write(npm1300_dev_st* dev, uint16_t reg, uint8_t val)

{

    /* 启动 */

    dev->start();

    /* 发送写地址 */

    if(0 != dev->write(NPM1300_WR_ADDR))

    {

        dev->stop();

        return -1;

    }

    /* 寄存器地址高字节 */

    if(0 != dev->write((reg>>8)&0xFF))

    {

        dev->stop();

        return -2;

    }

    /* 寄存器地址低字节 */

    if(0 != dev->write((reg>>0)&0xFF))

    {

        dev->stop();

        return -2;

    }

    /* 写数据 */

    if(0 != dev->write(val))

    {

        dev->stop();

        return -2;

    }


    /* 结束 */

    dev->stop();

    return 0;

}

/**

* \fn npm1300_init

* 初始化

* \param[in] dev \ref npm1300_dev_st

*/

void npm1300_init(npm1300_dev_st* dev)

{

    dev->init();

}

/**

* \fn npm1300_deinit

* 解除初始化

* \param[in] dev \ref npm1300_dev_st

*/

void npm1300_deinit(npm1300_dev_st* dev)

{

    dev->deinit();

}

Npm1300.h

#ifndef NPM1300_H

#define NPM1300_H

#ifdef __cplusplus

    extern "C"{

#endif

#include <stdint.h>

typedef void    (*npm1300_iic_start_pf)(void);                          /**< IIC启动接口 */

typedef void    (*npm1300_iic_stop_pf)(void);                           /**< IIC停止接口 */

typedef int     (*npm1300_iic_read_pf)(uint8_t* val, uint8_t ack);      /**< IIC读接口   */

typedef int     (*npm1300_iic_write_pf)(uint8_t val);                   /**< IIC写接口   */

typedef void    (*npm1300_iic_init_pf)(void);                           /**< 初始化接口 */

typedef void    (*npm1300_iic_deinit_pf)(void);                         /**< 解除初始化接口 */

typedef void    (*npm1300_iic_delay_us_pf)(uint32_t delay); /**< 延时接口      */

/**

* \struct npm1300_dev_st

* 接口结构体

*/

typedef struct

{

    npm1300_iic_start_pf  start;   /**< IIC启动接口 */

    npm1300_iic_stop_pf   stop;    /**< IIC停止接口 */

    npm1300_iic_read_pf   read;    /**< IIC读接口   */

    npm1300_iic_write_pf  write;   /**< IIC写接口   */

    npm1300_iic_init_pf   init;    /**< 初始化接口  */

    npm1300_iic_deinit_pf deinit;  /**< 解除初始化接口  */

    uint8_t              addr;     /**< 3位硬件地址    */

} npm1300_dev_st;

/**

* \fn npm1300_read

* 读数据

* \param[in] dev \ref npm1300_dev_st

* \param[in] reg 寄存器值

* \param[out] val 存读出的值

* \retval 0  成功

* \retval <0 失败

*/

int npm1300_read(npm1300_dev_st* dev, uint16_t reg, uint8_t* val);

/**

* \fn npm1300_write

* 写数据

* \param[in] dev \ref npm1300_dev_st

* \param[in] reg 寄存器值

* \param[in] val 待写入的值

* \retval 0  成功

* \retval <0 失败

*/

int npm1300_write(npm1300_dev_st* dev, uint16_t reg, uint8_t val);

/**

* \fn npm1300_init

* 初始化

* \param[in] dev \ref npm1300_dev_st

*/

void npm1300_init(npm1300_dev_st* dev);

/**

* \fn npm1300_deinit

* 解除初始化

* \param[in] dev \ref npm1300_dev_st

*/

void npm1300_deinit(npm1300_dev_st* dev);

#ifdef __cplusplus

    }

#endif

#endif

移植接口代码,仅需要移植io操作接口

npm1300_itf.c

#include "io_iic.h"

#include "npm1300.h"

#include "npm1300_itf.h"

#include "xx_gpio.h"

/* IIC IO操作的移植 */

static void io_iic_scl_write_port(uint8_t val)

{

    if(val)

    {

        xx_gpio_write(WQ_GPIO_09, 1);

    }

    else

    {

        xx_gpio_write(WQ_GPIO_09, 0);

    }

}

static void io_iic_sda_write_port(uint8_t val)

{

    xx_gpio_close(WQ_GPIO_07);

    xx_gpio_open(WQ_GPIO_07, WQ_GPIO_DIRECTION_OUTPUT);

    if(val)

    {

        xx_gpio_write(WQ_GPIO_07, 1);

    }

    else

    {

        xx_gpio_write(WQ_GPIO_07, 0);

    }

}

static void io_iic_sda_2read_port(void)

{

    xx_gpio_write(WQ_GPIO_07, 1);

    xx_gpio_close(WQ_GPIO_07);

    xx_gpio_open(WQ_GPIO_07, WQ_GPIO_DIRECTION_INPUT);

}

static uint8_t io_iic_sda_read_port(void)

{

    if(0 == xx_gpio_read(WQ_GPIO_07))

    {

        return 0;

    }

    else

    {

        return 1;

    }

}

static void io_iic_delay_us_port(uint32_t delay)

{

    uint32_t volatile t=delay;

    while(t--);

}

static void io_iic_init_port(void)

{

    xx_gpio_open(WQ_GPIO_07, WQ_GPIO_DIRECTION_OUTPUT);

    xx_gpio_open(WQ_GPIO_09, WQ_GPIO_DIRECTION_OUTPUT);

    xx_gpio_set_pull_mode(WQ_GPIO_07,WQ_GPIO_PULL_UP);

    xx_gpio_set_pull_mode(WQ_GPIO_09,WQ_GPIO_PULL_UP);

    xx_gpio_write(WQ_GPIO_07, 0);

    xx_gpio_write(WQ_GPIO_09, 0);

}

static void io_iic_deinit_port(void)

{

    xx_gpio_close(WQ_GPIO_07);

    xx_gpio_close(WQ_GPIO_09);

}

static io_iic_dev_st iic_dev=

{

    .scl_write = io_iic_scl_write_port,

    .sda_write = io_iic_sda_write_port,

    .sda_2read = io_iic_sda_2read_port,

    .sda_read = io_iic_sda_read_port,

    .delay_pf = io_iic_delay_us_port,

    .init = io_iic_init_port,

    .deinit = io_iic_deinit_port,

    .delayus = 500,

};

/* npm1300接口移植 */

static void npm1300_iic_start_port(void)

{

    io_iic_start(&iic_dev);

}

static void npm1300_iic_stop_port(void)

{

    io_iic_stop(&iic_dev);

}

static int npm1300_iic_read_port(uint8_t* val, uint8_t ack)

{

    return io_iic_read(&iic_dev,val,ack);

}

static int npm1300_iic_write_port(uint8_t val)

{

    return io_iic_write(&iic_dev,val);

}

static void npm1300_iic_init_port(void)

{

    io_iic_init(&iic_dev);

}

static void npm1300_iic_deinit_port(void)

{

    io_iic_deinit(&iic_dev);

}

npm1300_dev_st npm1300_dev=

{

     .start = npm1300_iic_start_port,

     .stop = npm1300_iic_stop_port,

     .read = npm1300_iic_read_port,

     .write = npm1300_iic_write_port,

     .init = npm1300_iic_init_port,

     .deinit = npm1300_iic_deinit_port,

     .addr = 0,

};

/* 对外接口 */

void npm1300_itf_init(void)

{

    npm1300_init(&npm1300_dev);

}

void npm1300_itf_deinit(void)

{

    npm1300_deinit(&npm1300_dev);

}

int npm1300_itf_write(uint16_t reg,uint8_t val)

{

    return npm1300_write(&npm1300_dev,reg,val);

}

int npm1300_itf_read(uint16_t reg,uint8_t* val)

{

    return npm1300_read(&npm1300_dev,reg,val);

}

npm1300_itf.h

#ifndef NPM1300_ITF_H

#define NPM1300_ITF_H

#ifdef __cplusplus

    extern "C"{

#endif

#include <stdint.h>

void npm1300_itf_init(void);

void npm1300_itf_deinit(void);

int npm1300_itf_write(uint16_t reg, uint8_t val);

int npm1300_itf_read(uint16_t reg,uint8_t* val);

#ifdef __cplusplus

    }

#endif

#endif

测试代码

初始化,main.c中包含头文件调用初始化

#include "npm1300_itf.h"

    npm1300_itf_init();

Shell命令行代码

shell_func.c种

包含头文件

#include "npm1300_itf.h"

命令列表添加两条命令

  { (uint8_t*)"npm1300rd",    npm1300rdfunc,      (uint8_t*)"npm1300rd reg"},

  { (uint8_t*)"npm1300wr",    npm1300wrfunc,      (uint8_t*)"npm1300wr reg val"},

实现命令函数

void npm1300rdfunc(uint8_t* param)

{

  int reg;

  uint8_t val;

  if(1 == sscanf((const char*)param, "%*s %x", &reg))

  {

    xprintf("read reg %x\r\n",reg);

    npm1300_itf_read(reg,&val);

    xprintf("%x\r\n",val);

  }

}

void npm1300wrfunc(uint8_t* param)

{

  int reg;

  int val;

  if(2 == sscanf((const char*)param, "%*s %x %x", &reg, &val))

  {

    xprintf("write reg %x val %x\r\n",reg, val);

    npm1300_itf_write(reg,val);

  }

}

五.测试

5.1读寄存器(读充电状态为例)

以读充电状态寄存器为例,bank为3,寄存器偏移为0x34,所以寄存器地址为0x334

155659yys11pjq0yfff1vx

155700bcm5ev400ufddcdv

命令行输入npm1300rd 334,读到结果是0x11,即电池状态连接,常压充电状态

155700mtibhwgmibcr08rm

抓取波形如下

155700rq7hhw5hm98aiwjg

5.2写寄存器(控制LED为例)

以操作LED0寄存器为例,一个模式寄存器控制模式,一个SET寄存器写1点亮,一个CLR寄存器写1熄灭。如果要使用SET和CLR寄存器控制,模式寄存器要配置为2.

寄存器bank为0xA,偏移分别为0x00,0x03和0x04,所以分别对应寄存器0xA00,0xA03和0xA04.

155701td3tcrzx28dtrt8f

155701qe3kikpzkmcuhui3

155701dslrbrmsja77bq7u

命令行输入

npm1300wr a00 2  //设置由SET和CLR寄存器控制

npm1300wr a03 1  //ERR红色灯亮

npm1300wr a04 1  //ERR红色灯灭

155701wvd37vb6y32vyrsr

抓包如下

155701dj8m8mr8t4uwgsha

155702r2bhabaw56b6ywa6

155702bfrhnoaahzrrd1rr

总结

手册描述很详细,参考手册可以很快的实现寄存器读写的驱动,

需要注意的是,手册中关于地址字节的W/R位的描述是反的。

另外寄存器是按照不同章节功能分开介绍的,不是集中在一起的。

七.参考

nPM1300_PS_v1.0.pdf