一、简介
4pin控制16ping,IO扩展器件
二、特性
- 16 个等电流输出通道
- 等电流输出值不受输出端负载电压影响等电流范围值,
- 3-30mA@VDp=5V;
- 3-15mA@Vpp=3.3V
- 极为精确的电流输出值,
- 通道间差异值: <±1.5%(一般值);<±2.5%(最大值);
- 芯片间差异值: <±1.5%(一般值);<±3.0% (最大值)。
- 利用一个外接电阻,可设定电流输出值
- 快速的输出电流响应, OE: 45ns (保持输出一致性的条件下)高达 25MHz 时钟频率
- 具 Schmitt trigger 输入
- 装置操作电压: 3.3/5 伏特
- 封装湿度敏感等级:3
三、 示例代码
/********************************************************************************
* @file extend_16ch.c
* @author jianqiang.xue
* @version V1.0.0
* @date 2023-04-07
* @brief 16位恒流驱动芯片 MBI5020 JXI5020GP
对于ARM_M平台 @16M
1个NOP:(1/24000000)*1000*1000*1000==41.67ns
__NOP(); __NOP(); __NOP(); __NOP(); __NOP(); \
对于n76e003平台 @16M
1个nop 占用87ns
while(1) 占用194ns
函数调用 占用570ns
如果没有APP_IO,则需要在外部实现该结构体
static const extend_16ch_gpio_t io = {
.clk_pin = {GPIOC, GPIO_PIN_5, GPIO_CLK(GPIOC)},
.sdi_pin = {GPIOC, GPIO_PIN_6, GPIO_CLK(GPIOC)},
.le_pin = {GPIOC, GPIO_PIN_4, GPIO_CLK(GPIOC)},
.oe_pin = {GPIOC, GPIO_PIN_3, GPIO_CLK(GPIOC)},
}
********************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
/* Private Includes ----------------------------------------------------------*/
#include "extend_16ch.h"
#include "bsp_gpio.h"
#ifdef LISUN_SDK
#include "ls_gpio.h"
#include "ls_syscfg.h"
#endif
/* Private Define ------------------------------------------------------------*/
/* Private Typedef -----------------------------------------------------------*/
/* Private Macro -------------------------------------------------------------*/
/* Private Variables ---------------------------------------------------------*/
#ifndef APP_IO
#define GPIO_APBx (0)
#else
#include "app_io.h"
#include "bsp_pwm.h"
#define PWMx g_io.type[io->oe_pin]-IO_TYPE_TIM1_CH1
#endif
/* Private Function Prototypes -----------------------------------------------*/
/* Public Function Prototypes ------------------------------------------------*/
/**
* @brief 器件硬件初始化
* @param *io: 引脚配置
*/
void extend_16ch_init(extend_16ch_gpio_t *io) {
#ifndef APP_IO
/* Enable the GPIO Clock */
bsp_gpio_set_clk(GPIO_APBx, io->clk_pin.periph, true);
/* Configure the GPIO pin */
bsp_gpio_init_output(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_OUT_PP);
/* Reset PIN to switch off the */
bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
/* Enable the GPIO Clock */
bsp_gpio_set_clk(GPIO_APBx, io->sdi_pin.periph, true);
/* Configure the GPIO pin */
bsp_gpio_init_output(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_OUT_PP);
/* Reset PIN to switch off the */
bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
/* Enable the GPIO Clock */
bsp_gpio_set_clk(GPIO_APBx, io->le_pin.periph, true);
/* Configure the GPIO pin */
bsp_gpio_init_output(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_OUT_PP);
/* Reset PIN to switch off the */
bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
/* Enable the GPIO Clock */
bsp_gpio_set_clk(GPIO_APBx, io->oe_pin.periph, true);
/* Configure the GPIO pin */
bsp_gpio_init_output(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_OUT_PP);
/* Reset PIN to switch off the */
bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
#else
#endif
}
/**
* @brief 注销器件引脚
* @param *io: 引脚配置
*/
void extend_16ch_deinit(extend_16ch_gpio_t *io) {
#ifndef APP_IO
/* Turn off */
bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
/* DeInit the GPIO pin */
bsp_gpio_deinit(io->clk_pin.port, io->clk_pin.pin);
/* Turn off */
bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
/* DeInit the GPIO pin */
bsp_gpio_deinit(io->sdi_pin.port, io->sdi_pin.pin);
/* Turn off */
bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
/* DeInit the GPIO pin */
bsp_gpio_deinit(io->le_pin.port, io->le_pin.pin);
/* Turn off */
bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
/* DeInit the GPIO pin */
bsp_gpio_deinit(io->oe_pin.port, io->oe_pin.pin);
#else
#endif
}
/**
* @brief 写入数据
* @param *io: 引脚配置
* @param data[]: IO数据,请以倒叙传入。如U5,U4,U3,U2,U1。
* @param num: 器件数量
*/
void extend_16ch_write(extend_16ch_gpio_t *io, uint16_t data[], uint8_t num) {
//extend_16ch_close(io);
uint16_t temp = 0;
uint8_t bit_val = 0;
#ifndef APP_IO
// 先关闭器件
bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
for (uint8_t i = 0; i < num; i++) {
temp = data[i];
for (uint8_t bit = 0; bit < 16; bit++) {
bit_val = temp & 0x8000 ? 1 : 0;
temp <<= 1;
if (bit_val)
bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_SET);
else
bsp_gpio_set_pin(io->sdi_pin.port, io->sdi_pin.pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_SET);
__NOP();__NOP();
bsp_gpio_set_pin(io->clk_pin.port, io->clk_pin.pin, BSP_GPIO_PIN_RESET);
__NOP();__NOP();
}
}
bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_SET);
__NOP();
bsp_gpio_set_pin(io->le_pin.port, io->le_pin.pin, BSP_GPIO_PIN_RESET);
__NOP();__NOP();
#else
// 先关闭器件
bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_RESET);
for (uint8_t i = 0; i < num; i++) {
temp = data[i];
for (uint8_t bit = 0; bit < 16; bit++) {
bit_val = temp & 0x8000 ? 1 : 0;
temp <<= 1;
if (bit_val)
bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_SET);
else
bsp_gpio_set_pin(g_io_cfg[io->sdi_pin].port, g_io_cfg[io->sdi_pin].pin, BSP_GPIO_PIN_RESET);
bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_SET);
__NOP();__NOP();
bsp_gpio_set_pin(g_io_cfg[io->clk_pin].port, g_io_cfg[io->clk_pin].pin, BSP_GPIO_PIN_RESET);
__NOP();__NOP();
}
}
bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_SET);
__NOP();
bsp_gpio_set_pin(g_io_cfg[io->le_pin].port, g_io_cfg[io->le_pin].pin, BSP_GPIO_PIN_RESET);
__NOP();__NOP();
#endif
//extend_16ch_open(io);
}
/**
* @brief 器件使能脚--打开
* @param io 引脚配置
*/
void extend_16ch_open(extend_16ch_gpio_t *io) {
#ifndef APP_IO
bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_RESET);
#else
if (g_io.type[io->oe_pin] == IO_TYPE_OUT_PP) {
if (io->valid_level)
bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_SET);
else
bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_RESET);
} else { // 非输出脚,则为PWM模式
if (io->valid_level)
bsp_pwm_set_pulse(PWMx, bsp_pwm_pp_to_pulse(PWMx, io->intensity_ctrl));
else
bsp_pwm_set_pulse(PWMx, bsp_pwm_pp_to_pulse(PWMx, 100 - io->intensity_ctrl));
}
#endif
}
/**
* @brief 器件使能脚--关闭
* @param io 引脚配置
*/
void extend_16ch_close(extend_16ch_gpio_t *io) {
#ifndef APP_IO
bsp_gpio_set_pin(io->oe_pin.port, io->oe_pin.pin, BSP_GPIO_PIN_SET);
#else
if (g_io.type[io->oe_pin] == IO_TYPE_OUT_PP) {
if (io->valid_level)
bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_RESET);
else
bsp_gpio_set_pin(g_io_cfg[io->oe_pin].port, g_io_cfg[io->oe_pin].pin, BSP_GPIO_PIN_SET);
} else {
if (io->valid_level)
bsp_pwm_set_pulse(PWMx, 0);
else
bsp_pwm_set_pulse(PWMx, -1);
}
#endif
}
/********************************************************************************
* @file extend_16ch.h
* @author jianqiang.xue
* @version V1.0.0
* @date 2023-04-07
* @brief 16位恒流驱动芯片 MBI5020 JXI5020GP
如果没有APP_IO则使用下面方式定义引脚:
static const extend_16ch_gpio_t io = {
.clk_pin = {GPIOC, GPIO_PIN_5, GPIO_CLK(GPIOC)},
.sdi_pin = {GPIOC, GPIO_PIN_6, GPIO_CLK(GPIOC)},
.le_pin = {GPIOC, GPIO_PIN_4, GPIO_CLK(GPIOC)},
.oe_pin = {GPIOC, GPIO_PIN_3, GPIO_CLK(GPIOC)},
};
如果启动了APP_IO则直接用ID号
#define LS_EXIO_CLK_ID (7)
#define LS_EXIO_DIO_ID (8)
#define LS_EXIO_LE_ID (6)
#define LS_EXIO_OE_ID (5)
static const extend_16ch_gpio_t io = {
.clk_pin = LS_EXIO_CLK_ID,
.sdi_pin = LS_EXIO_DIO_ID,
.le_pin = LS_EXIO_LE_ID,
.oe_pin = LS_EXIO_OE_ID,
};
********************************************************************************/
#ifndef __EXTEND_16CH_H
#define __EXTEND_16CH_H
/* Includes ------------------------------------------------------------------*/
#include <stdint.h>
#include <stdbool.h>
#include "bsp_gpio.h"
/* Public enum ---------------------------------------------------------------*/
/* Public Struct -------------------------------------------------------------*/
#ifndef APP_IO
typedef struct {
bsp_gpio2_t clk_pin; // 时钟脚
bsp_gpio2_t sdi_pin; // 数据脚
bsp_gpio2_t le_pin; // 锁存 低电平开始准备数据,高电平发送数据
bsp_gpio2_t oe_pin; // 使能脚 低电平打开IO0-IO15的输入,高电平关闭
} extend_16ch_gpio_t;
#else
typedef struct { // 填写[g_io_cfg]中索引号
uint8_t clk_pin;
uint8_t sdi_pin;
uint8_t le_pin;
uint8_t oe_pin; // 请在syscfg_gui中配置为PWM
uint8_t intensity_ctrl; // 亮度控制,通过调整[oe_pin]占空比
uint8_t valid_level; // 有效电平
} extend_16ch_gpio_t;
#endif
/* Public Function Prototypes ------------------------------------------------*/
void extend_16ch_init(extend_16ch_gpio_t *io);
void extend_16ch_deinit(extend_16ch_gpio_t *io);
void extend_16ch_write(extend_16ch_gpio_t *io, uint16_t data[], uint8_t num);
void extend_16ch_open(extend_16ch_gpio_t *io);
void extend_16ch_close(extend_16ch_gpio_t *io);
#endif