diff --git a/zh-cn/device-dev/driver/Readme-CN.md b/zh-cn/device-dev/driver/Readme-CN.md index 1db6007a4f7910b431d957c70cecc76c883c36b4..b021fe5cb3a35c32bdd0d2607f157405257fcc4b 100755 --- a/zh-cn/device-dev/driver/Readme-CN.md +++ b/zh-cn/device-dev/driver/Readme-CN.md @@ -22,6 +22,7 @@ - [SPI](driver-platform-spi-develop.md) - [UART](driver-platform-uart-develop.md) - [WatchDog](driver-platform-watchdog-develop.md) + - [I2S](driver-platform-i2s-develop.md) - [平台驱动使用](driver-platform.md) - [ADC](driver-platform-adc-des.md) - [GPIO](driver-platform-gpio-des.md) @@ -36,6 +37,7 @@ - [SPI](driver-platform-spi-des.md) - [UART](driver-platform-uart-des.md) - [WATCHDOG](driver-platform-watchdog-des.md) + - [I2S](driver-platform-i2s-des.md) - [外设驱动使用](driver-peripherals.md) - [LCD](driver-peripherals-lcd-des.md) - [TOUCHSCREEN](driver-peripherals-touch-des.md) diff --git a/zh-cn/device-dev/driver/driver-develop.md b/zh-cn/device-dev/driver/driver-develop.md index e4cee0c88383f41bd46628a0b0dfd079876f805c..6162a4129fe5578cb1144bf35b3757239e5455d8 100644 --- a/zh-cn/device-dev/driver/driver-develop.md +++ b/zh-cn/device-dev/driver/driver-develop.md @@ -27,3 +27,5 @@ - **[UART](driver-platform-uart-develop.md)** - **[WatchDog](driver-platform-watchdog-develop.md)** + +- **[I2S](driver-platform-i2s-develop.md)** diff --git a/zh-cn/device-dev/driver/driver-platform-i2s-des.md b/zh-cn/device-dev/driver/driver-platform-i2s-des.md new file mode 100755 index 0000000000000000000000000000000000000000..39863601e3dfe14be875298625f7fcde8279e021 --- /dev/null +++ b/zh-cn/device-dev/driver/driver-platform-i2s-des.md @@ -0,0 +1,684 @@ +# I2S + +- [概述](#section193356154511) +- [接口说明](#section1325964832615) +- [使用指导](#section71363452477) + - [使用流程](#section32846814820) + - [获取I2S设备句柄](#section1927265711481) + - [设置I2S设备属性](#section541133418493) + - [获取I2S设备属性](#section7870106145010) + - [使能I2S设备](#section13324155195013) + - [禁用I2S设备](#section19661632135117) + - [开始I2S设备读功能](#section19661632135118) + + - [停止I2S设备读功能](#section19661632135119) + - [开始I2S设备写功能](#section19661632135120) + - [停止I2S设备写功能](#section19661632135121) + - [I2S读](#section19661632135122) + - [I2S写](#section19661632135123) + - [销毁I2S设备句柄](#section19661632135124) +- [使用实例](#section06541058155120) + +## 概述 + +- I2S(Inter-IC Sound)总线, 又称集成电路内置音频总线,是飞利浦半导体公司(现为恩智浦半导体公司)针对数字音频设备之间的音频数据传输而制定的一种总线标准。该总线专门用于音频设备之间的数据传输,广泛应用于各种多媒体系统。采用了沿独立的导线传输时钟与数据信号的设计,通过将数据和时钟信号分离,避免了因时差诱发的失真。 +- I2S信号线,串行时钟SCK,也叫位时钟BCLK,对应数字音频的每一位数据。SCK的频率 = 声道数 * 采样频率 * 采样位数。字段选择信号WS,也叫LRCLK,用于切换左右声道的数据,字段选择信号WS表明了正在被传输的声道,WS为0,表示正在传输的是左声道的数据,WS为1,表示正在传输的是右声道的数据。WS的频率 = 采样频率。串行数据SD,就是用二进制补码表示的音频数据。I2S串行数据在传输的时候,由高位(MSB)到低位(LSB)依次进行传输。 +- 能够产生SCK和WS的信号端就是主设备,用MASTER表示,通信示意图如下: + +**图 1** master是transmitter时的通信示意图 + +![](figures/I2S-master是transmiter.png) + +**图 2** master是receiver时的通信示意图 + +![](figures/I2S-master是receiver.png) + +**图 3** master是controller时的通信示意图 + +![](figures/I2S-master是controller.png) + +## 接口说明 + +**表 1** I2S驱动API接口功能介绍: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

功能分类

+

接口名

+

描述

+

I2S设备句柄获取、释放接口

+

I2sOpen

+

获取I2S设备句柄

+

I2sClose

+

释放I2S设备句柄

+

I2S使能、禁用接口

+

+

I2sEnable

+

使能I2S设备

+

I2sDisable

+

禁用I2S设备

+

I2S开始读、写接口

+

+

I2sStartRead

+

I2S开始读

+

I2sStartWrite

+

I2S开始写

+

I2S停止读、写接口

+

+

I2sStopRead

+

I2S停止读

+

I2sStopWrite

+

I2S停止写

+

I2S读写接口

+

+

I2sRead

+

I2S读

+

I2sWrite

+

I2S写

+

I2S获取/设置设备属性

+

+

I2sGetCfg

+

I2S获取设备属性

+

I2sSetCfg

+

I2S设置设备属性

+
+ +>![](../public_sys-resources/icon-note.gif) **说明:** +>本文涉及的所有接口,仅限内核态使用,不支持在用户态使用。 + +## 使用指导 + +### 使用流程 + +使用I2S的一般流程如[图4](#fig1586912310348)所示。 + +**图 4** I2S使用流程图 +![](figures/I2S使用流程图.png) + +### 获取I2S设备句柄 + +在使用I2S进行通信时,首先要调用I2sOpen获取I2S设备句柄,该函数会返回指定编号的I2S设备句柄。 + +DevHandle I2sOpen(int16_t number); + +**表 2** I2sOpen参数和返回值描述 + + + + + + + + + + + + + + + + + + +

参数

+

参数描述

+

number

+

I2S设备编号

+

返回值

+

返回值描述

+

NULL

+

获取I2S设备句柄失败

+

设备句柄

+

对应的I2S设备句柄

+
+ +假设系统中存在8个I2S控制器,编号从0到7,获取3号控制器设备句柄示例如下: + +```c +DevHandle i2sHandle = NULL; /* I2C控制器句柄 */ +/* 打开I2C控制器 */ +i2sHandle = I2sOpen(3); +if (i2sHandle == NULL) { + HDF_LOGE("I2sOpen: failed\n"); + return; +} +``` + +### 设置[I2S]()设备属性 + +在使用I2S进行通信前,需要调用I2sSetCfg设置I2S设备属性。设置I2S设备属性函数如下: + +void I2sSetCfg(DevHandle handle, struct I2sCfg *cfg); + +**表 3** I2sSetCfg参数和返回值描述 + + + + + + + + + + + + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+

cfg

+

I2S设备配置参数

+

返回值

+

返回值描述

+

0

+

获取配置成功

+

负数

+

获取配置失败

+
+ +```c +struct I2sCfg cfg; + cfg.sampleRate = test->sampleRate; + cfg.type = test->type; + cfg.channelMode = test->channelMode; + cfg.samplePrecision = test->samplePrecision; + cfg.channelIfMode = test->channelIfMode; + cfg.mclk = test->mclk; + cfg.bclk = test->bclk; + cfg.writeChannel = test->writeChannel; + cfg.i2slFsSel = test->i2slFsSel; + cfg.width = I2S_WORDWIDTH_16BIT; + I2sSetCfg(test->handle, &cfg); +``` + +### 获取I2S设备属性 + +设置I2S属性成功后,可以通过获取设备属性接口查看I2S设备属性。获取I2S设备属性的函数如下所示: + +void I2sGetCfg(DevHandle handle, struct I2sCfg *cfg); + +**表 4** I2sGetCfg参数和返回值描述 + + + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+

cfg

+

I2S设备配置参数

+
+ +```c +struct I2sCfg cfg; +I2sGetCfg(test->handle, &cfg); +HDF_LOGE("%s:sampleRate[%u], type[%u], channelMode[%u], samplePrecision[%u],\ + channelIfMode[%u], mclk[%u], bclk[%u], writeChannel[%u], i2slFsSel[%u]", __func__, + test->sampleRate, test->type, test->channelMode, test->samplePrecision, + test->channelIfMode, test->mclk, test->bclk, test->writeChannel, test->i2slFsSel); +``` + +### 使能I2S设备 + +- 在使用I2S进行通信前必须使能I2S设备,通过调用I2sEnable使能I2S设备。使能I2S设备的函数如下所示: + +void I2sEnable(DevHandle handle); + +**表 5** I2sEnable参数和返回值描述 + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL || test->wbuf == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +I2sEnable(test->handle); +``` + +### 禁用I2S设备 + +需要禁用I2S设备时可以通过调用I2sDisable来实现。禁用I2S设备的函数如下所示: + +void I2sDisable(DevHandle handle) ; + +**表 6** I2sDisable参数描述 + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL || test->wbuf == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +I2sDisable(test->handle); +``` + +### 开始I2S读功能 + +在进行读I2S从设备之前需要调用函数I2sStartRead向I2S从设备发送开始读命令来开始读的功能。开始I2S设备读的函数如下所示: + +void I2sStartRead(DevHandle handle); + +**表 7** I2sStartRead参数描述 + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +HDF_LOGI("%s: rbuf[%p] wbuf[%p]\n", __func__, test->rbuf, test->wbuf); +I2sStartRead(test->handle); +``` + +### 停止I2S读功能 + +在读取从设备结束之前需要调用I2sStopRead函数发送停止读的命令来停止读功能。停止I2S设备读的函数如下所示: + +void I2sStopRead(DevHandle handle); + +**表 8** I2sStopRead参数描述 + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +HDF_LOGI("%s: rbuf[%p] wbuf[%p]\n", __func__, test->rbuf, test->wbuf); +I2sStopRead(test->handle); +``` + +### 开始I2S写功能 + +在进行写I2S从设备之前需要调用函数I2sStartWrite向I2S从设备发送开始写命令来开始写功能。开始I2S写功能的函数如下所示: + +void I2sStartWrite(DevHandle handle); + +**表 9** I2sStartWrite参数描述 + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +I2sStartWrite(test->handle); +``` + +### 停止I2S写功能 + +在写从设备结束之前需要调用函数I2sStopWrite向I2S从设备发送停止写的命令来停止写功能。停止I2S写功能的函数如下所示: + +void I2sStopWrite(DevHandle handle); + +**表 10** I2sStopWrite参数描述 + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +```c +if (test == NULL || test->handle == NULL) { + HDF_LOGE("%s: test null", __func__); + return HDF_ERR_INVALID_OBJECT; + } +I2sStopWrite(test->handle); +``` + +### I2S读 + +通过调用函数I2sRead读取I2S从设备的数据,I2S读函数如下所示: + +int32_t I2sRead(DevHandle handle, uint8_t *buf, uint32_t len, uint32_t *pRlen) ; + +**表 11** I2sRead参数描述 + + + + + + + + + + + + + + + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+

buf

+

接收读取数据的指针

+

len

+

读buffers的长度

+

pRlen

+

每次实际读的长度

+

返回值

+

返回值描述

+

HDF_SUCCESS

+

表示读取成功

+

HDF_FAILURE

+

表示读取失败

+
+ +```c +if (I2sRead(test->handle, test->rbuf, test->len, &test->len) != HDF_SUCCESS) { + HDF_LOGE("%s: I2sRead error \n", __func__); + return HDF_FAILURE; + } +``` + +### I2S写 + +通过调用函数I2sWrite向I2S从设备写数据,I2S写的函数如下所示: + +int32_t I2sWrite(DevHandle handle, uint8_t *buf, uint32_t len, uint32_t *pWlen) ; + +**表 12** I2sWrite参数描述 + + + + + + + + + + + + + + + + + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+

buf

+

写数据的指针

+

len

+

写buffers的长度

+

pWlen

+

每次实际写的长度

+

返回值

+

返回值描述

+

HDF_SUCCESS

+

表示写成功

+

HDF_FAILURE

+

表示写失败

+
+ +```c +if (I2sWrite(test->handle, test->wbuf, test->len, &test->len) != HDF_SUCCESS) { + HDF_LOGE("%s: I2sWriteTest error \n", __func__); + return HDF_FAILURE; + } +``` + +### 销毁I2S设备句柄 + +在使用I2S通信结束后需要调用函数I2sClose销毁I2S设备句柄,销毁I2S设备句柄的函数如下所示: + +void I2sClose(DevHandle handle); + +**表 13** I2sClose参数描述 + + + + + + + + +

参数

+

参数描述

+

handle

+

I2S设备句柄

+
+ +``` +I2sClose(test->handle); +``` + +## 使用实例 + +I2S设备完整的使用实例如下,首先需要获取I2S设备句柄,接着设置I2S设备属性、使能I2S设备,开始I2S读、写功能,进行I2S读、写,停止I2S读、写功能,禁用I2S设备,销毁I2S设备句柄。 + +```c +#include "hdf_log.h" +#include "i2s_if.h" +void I2sTestSample(void) +{ + int32_t ret; + int32_t i; + int16_t number; + DevHandle handle = NULL; + uint8_t wbuff[5] = { 1, 2, 3, 4, 5 }; + uint8_t rbuff[5] = { 0 }; + uint32_t wlen = 0; + uint32_t pRlen = 0; + struct I2sCfg cfg; + cfg.sampleRate = I2S_SAMPLE_RATE_44_1K; /* I2S采样速率,这里设置的是44.1k速率采样 */ + cfg.type = I2S_PROTOCOL_I2S_MSB; /* I2S 协议传输类型 ,这里设置的协议类型是msb,先传输高字节后传输低字节 */ + cfg.channelMode = I2S_CHANNEL_MODE_STEREO; /* I2S通道模式,这里设置的是立体声通道模式 */ + cfg.samplePrecision = 8; /* I2S采样精度,这里设置的是8bit,位数越高声音的保真度越高 */ + cfg.channelIfMode = I2S_CHANNEL_IF_MODE_I2S; /* I2S协议时序模式,这里设置的是I2S协议时序 */ + cfg.mclk = 256; /* I2S同步时钟频率,这里设置的是256khz */ + cfg.bclk = 32768; /* I2S串行时钟频率,这里设置的是32768hz */ + cfg.writeChannel = I2S_WRITE_CHANNEL_AUDIO; /* I2S 写通道,这里设置的是音频通道 */ + cfg.i2slFsSel = I2SL_FS_SEL_1024_FS /* I2S采样频率设置,这里设置的采样频率是1024hz */; + cfg.width = I2S_WORDWIDTH_16BIT; /* I2S传输的位宽,这里设置的是16bit */ + number = 0; /* I2S设备号,要填写实际平台上的设备号 */ + handle = I2sOpen(number); /* 获取I2S设备句柄 */ + if (handle == NULL) { + HDF_LOGE("I2sOpen: failed!\n"); + return; + } + /* 设置I2S设备属性 */ + ret = I2sSetCfg(handle, &cfg); + if (ret != 0) { + HDF_LOGE("I2sSetCfg: failed, ret %d\n", ret); + goto _ERR; + } + /* 使能I2S设备 */ + I2sEnable(handle); + /* 开始I2S写功能 */ + I2sStartWrite(handle); + /* 向I2S设备写5字节的数据 */ + ret = I2sWrite(handle, wbuff, 5, &wlen); + if (ret < 0) { + HDF_LOGE("I2sWrite: failed, ret %d\n", ret); + goto _ERR; + } + /* 停止I2S写功能 */ + I2sStopWrite(handle); + /* 开始I2S读功能 */ + I2sStartRead(handle); + /* 从I2S设备读5字节的数据 */ + ret = I2sRead(handle, rbuff, 5, &pRlen); + if (ret < 0) { + HDF_LOGE("I2sRead: failed, ret %d\n", ret); + goto _ERR; + } + /* 停止I2S读功能 */ + I2sStopRead(handle); + for (i = 0; i < 5; i++) { + HDF_LOGE("%s: rbuff[%d] = 0x%x", __func__, i, rbuff[i]); + } + /* 禁用I2S设备 */ + I2sDisable(handle); +_ERR: + /* 销毁I2S设备句柄 */ + I2sClose(handle); +} +``` + diff --git a/zh-cn/device-dev/driver/driver-platform-i2s-develop.md b/zh-cn/device-dev/driver/driver-platform-i2s-develop.md new file mode 100755 index 0000000000000000000000000000000000000000..ea1d8e85de9b4dab8770369826c970922d2305db --- /dev/null +++ b/zh-cn/device-dev/driver/driver-platform-i2s-develop.md @@ -0,0 +1,483 @@ +# I2S + +- [概述](#section84922229152909) +- [接口说明](#section752964871810) +- [开发步骤](#section799667984152909) +- [开发实例](#section956157227152909) + +## 概述 + +I2S(Inter—IC Sound)总线, 又称集成电路内置音频总线,在HDF框架中,I2S的接口适配模式采用独立服务模式,在这种模式下,每一个设备对象会独立发布一个设备服务来处理外部访问,设备管理器收到API的访问请求之后,通过提取该请求的参数,达到调用实际设备对象的相应内部方法的目的。独立服务模式可以直接借助HDFDeviceManager的服务管理能力,但需要为每个设备单独配置设备节点,增加内存占用。 + +**图 1** I2S独立服务模式结构图 +![](figures/独立服务模式结构图.png) + +## 接口说明 + +I2sCntlrMethod定义: + +```c +struct I2sCntlrMethod { + int32_t (*GetCfg)(struct I2sCntlr *, struct I2sCfg *); + int32_t (*SetCfg)(struct I2sCntlr *, struct I2sCfg *); + int32_t (*Transfer)(struct I2sCntlr *, struct I2sMsg *); + int32_t (*Open)(struct I2sCntlr *); + int32_t (*Close)(struct I2sCntlr *); + int32_t (*Enable)(struct I2sCntlr *); + int32_t (*Disable)(struct I2sCntlr *); + int32_t (*StartWrite)(struct I2sCntlr *); + int32_t (*StopWrite)(struct I2sCntlr *); + int32_t (*StartRead)(struct I2sCntlr *); + int32_t (*StopRead)(struct I2sCntlr *); +}; +``` + +**表 1** I2sCntlrMethod结构体成员的回调函数功能说明 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

成员函数

+

入参

+

出参

+

返回值

+

功能

+

GetCfg

+

Cntlr:结构体指针,核心层i2s控制器;

+

Cfg:结构体指针,传出的属性值(见i2s_if.h中I2sCfg定义)

+

HDF_STATUS相关状态

+

获取属性值

+

SetCfg

+

Cfg:结构体指针,传入的属性值(见i2s_if.h中I2sCfg定义)

+

Cntlr:结构体指针,核心层i2s控制器,传出的值

+

HDF_STATUS相关状态

+

设置控制器属性

+

Transfer

+

Cntlr:结构体指针,核心层i2s控制器;Msgs:消息结构体指针

+

+

HDF_STATUS相关状态

+

i2s数据传输

+

Open

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

打开I2S

+

Close

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

关闭I2S

+

Enable

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

使能I2S设备

+

Disable

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

禁用I2S设备

+

StartWrite

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

开始写

+

StopWrite

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

停止写

+

StartRead

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

开始读

+

StopRead

+

cntlr:结构体指针,核心层i2s控制器;

+

+

HDF_STATUS相关状态

+

停止读

+
+ +## 开发步骤 + +I2S模块适配HDF框架的三个环节是配置属性文件,实例化驱动入口,以及实例化核心层接口函数。 + +1. **实例化驱动入口:** + - 实例化HdfDriverEntry结构体成员。 + - 调用HDF\_INIT将HdfDriverEntry实例化对象注册到HDF框架中。 + +2. **配置属性文件:** + - 在device\_info.hcs文件中添加deviceNode描述。 + - 【可选】添加i2s\_config.hcs器件属性文件。 + +3. **实例化I2S控制器对象:** + + - 初始化I2sCntlr成员。 + - 实例化I2sCntlr成员I2sCntlrMethod。 + +>​ ![](../public_sys-resources/icon-note.gif) **说明:** +>​ 实例化I2sCntlr成员I2sCntlrMethod,其定义和成员说明见[接口说明](#section752964871810)。 + + +4. **驱动调试:** + + 【可选】针对新增驱动程序,建议验证驱动基本功能,例如设置I2S属性,获取I2S属性等。 + + +## 开发实例 + +下方将以i2s_hi35xx.c为示例,展示需要厂商提供哪些内容来完整实现设备功能。 + +1. 驱动开发首先需要实例化驱动入口,驱动入口必须为HdfDriverEntry(在 hdf\_device\_desc.h 中定义)类型的全局变量,且moduleName要和device\_info.hcs中保持一致。HDF框架会将所有加载的驱动的HdfDriverEntry对象首地址汇总,形成一个类似数组的段地址空间,方便上层调用。 + + 一般在加载驱动时HDF会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出。 + + I2S驱动入口参考: + + ```c + struct HdfDriverEntry g_hdfI2sDevice = { + .moduleVersion = 1, + .moduleName = "HDF_PLATFORM_I2S",//【必要且与 HCS 里面的名字匹配】 + .Bind = HdfI2sDeviceBind,//见Bind参考 + .Init = HdfI2sDeviceInit, //见Init参考 + .Release = HdfI2sDeviceRelease, //见Release参考 + }; + //调用HDF_INIT将驱动入口注册到HDF框架中 + HDF_INIT(g_hdfI2sDevice); + ``` + +2. 完成驱动入口注册之后,下一步请在device\_info.hcs文件中添加deviceNode信息,并在 i2s_config.hcs 中配置器件属性。deviceNode信息与驱动入口注册相关,器件属性值与核心层I2sCntlr成员的默认值或限制范围有密切关系。 + + 本例只有一个I2S控制器,如有多个器件信息,则需要在device\_info文件增加deviceNode信息,以及在i2s_config文件中增加对应的器件属性。 + + - device\_info.hcs 配置参考。 + + ``` + root { + device_info { + match_attr = "hdf_manager"; + platform :: host { + hostName = "platform_host"; + priority = 50; + device_i2s :: device { + device0 :: deviceNode { + policy = 1; + priority = 60; + permission = 0644; + moduleName = "HDF_PLATFORM_I2S"; + serviceName = "HDF_PLATFORM_I2S_0"; + deviceMatchAttr = "hisilicon_hi35xx_i2s_0"; + } + } + + } + } + } + ``` + + - i2s_config.hcs 配置参考。 + + ``` + root { + platform { + i2s_config {//每一个I2S控制器配置私有数据 + template i2s_controller {//模板公共参数, 继承该模板的节点如果使用模板中的默认值, 则节点字段可以缺省 + serviceName = ""; + match_attr = ""; + busNum = 0; // 总线号 + i2s_pad_enable = 1; + audio_enable = 0; + regBase = 0x113B0000;// 地址映射需要 + PERI_CRG103 = 0xa; + MCLK = 12288; /* KHZ */ + aiao_srst_req = 1; /* 1 reset-->RX0 channel reset */ + aiao_cken = 0; /* 0 close MCLK/BCLK/WS clk gate */ + BCLK = 3072; /* KHZ */ + i2sl_fs_sel = 0x1a; /* MCLK=256fs */ + irqNum = 0; // 中断号 + } + + controller_0x113b0000 :: i2s_controller { + busNum = 0; //【必要】总线号 + regBase = 0x113B0000; // 地址映射需要 + match_attr = "hisilicon_hi35xx_i2s_0"; + irqNum = 87; // 中断号 + } + ... + // 【可选】可新增,但需要在 device_info.hcs 添加对应的节点 + } + } + } + ``` + +3. 完成驱动入口注册之后,最后一步就是以核心层I2sCntlr对象的初始化为核心,包括厂商自定义结构体(传递参数和数据),实例化I2sCntlr成员I2sCntlrMethod(让用户可以通过接口来调用驱动底层函数),实现HdfDriverEntry成员函数(Bind,Init,Release)。 + - 自定义结构体参考 + + 从驱动的角度看,自定义结构体是参数和数据的载体,而且i2s_config.hcs文件中的数值会被HDF读入通过DeviceResourceIface来初始化结构体成员,一些重要数值也会传递给核心层对象,例如设备号、总线号等。 + + ```c + struct I2sConfigInfo {//对应于hcs中的参数 + uint8_t i2sPadEnable; + uint8_t audioEnable; + uint32_t PERICRG103; + uint32_t I2sCfgCfg000; + uint32_t mclk; /**< KHZ */ + uint32_t bclk; /**< KHZ */ + struct I2sCfgCfg100 regCfg100; + struct RxIfAttr1Info regRxIfAttr1; + volatile unsigned char *phyBase; + volatile unsigned char *regBase; + enum I2sWriteChannel writeChannel; + enum I2sSampleRate sampleRate; + enum I2sWordWidth width; + enum I2sChannelIfMode channelIfMode; + enum I2sChannelMode channelMode; + enum I2sProtocolType type; + uint8_t samplePrecision; + uint16_t i2slFsSel; + DMA_ADDR_T rxData; + uint8_t *rxVirData; + uint32_t rxWptr; + uint32_t rxRptr; + uint32_t rxSize; + uint32_t rxTransSize; + DMA_ADDR_T txData; + uint8_t *txVirData; + uint32_t txWptr; + uint32_t txRptr; + uint32_t txSize; + uint32_t txTransSize; + volatile unsigned char *codecAddr; + volatile unsigned char *crg103Addr; + bool isplay; + bool txEn; + }; + + //I2sCntlr 是核心层控制器结构体,其中的成员在Init函数中会被赋值 + struct I2sCntlr { + struct IDeviceIoService service; + struct HdfDeviceObject *device; + uint32_t busNum; + uint32_t irqNum; + struct OsalMutex lock; + struct I2sCntlrMethod *method; + void *priv; // private data + }; + ``` + + - I2sCntlr 成员回调函数结构体I2sCntlrMethod的实例化,其他成员在Init函数中初始化。 + + ```c + struct I2sCntlrMethod g_i2sCntlrMethod = {// i2s_hi35xx.c 中的示例:钩子函数的实例化 + .GetCfg = Hi35xxI2sGetCfg, + .SetCfg = Hi35xxI2sSetCfg, + .Transfer = Hi35xxI2sTransfer, + .Open = Hi35xxI2sOpen, + .Close = Hi35xxI2sClose, + .Enable = Hi35xxI2sEnable, + .Disable = Hi35xxI2sDisable, + .StartWrite = Hi35xxI2sStartWrite, + .StopWrite = Hi35xxI2sStopWrite, + .StartRead = Hi35xxI2sStartRead, + .StopRead = Hi35xxI2sStopRead, + }; + ``` + + - Bind 函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF\_STATUS相关状态。 + + 函数说明: + + 将 I2sCntlr 对象同 HdfDeviceObject 进行了关联。 + + ```c + static int32_t HdfI2sDeviceBind(struct HdfDeviceObject *device) + { + if (device == NULL) { + I2S_PRINT_LOG_ERR("%s: device NULL", __func__); + return HDF_ERR_INVALID_OBJECT; + } + return (I2sCntlrCreate(device) == NULL) ? HDF_FAILURE : HDF_SUCCESS; + } + struct I2sCntlr *I2sCntlrCreate(struct HdfDeviceObject *device) + { + struct I2sCntlr *cntlr = NULL; + ... + cntlr = (struct I2sCntlr *)OsalMemCalloc(sizeof(*cntlr)); + if (cntlr == NULL) { + HDF_LOGE("%s: OsalMemCalloc error", __func__); + return NULL; + } + ... + cntlr->device = device; + device->service = &(cntlr->service); + (void)OsalMutexInit(&cntlr->lock); + cntlr->priv = NULL; + cntlr->method = NULL; + return cntlr; + } + ``` + + - Init函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + HDF\_STATUS相关状态 (下表为部分展示,如需使用其他状态,可见/drivers/framework/include/utils/hdf\_base.h中HDF\_STATUS 定义)。 + + **表 2** init函数入参和返回值 + + + + | 状态(值) | 问题描述 | + | ---------------------- | -------------- | + | HDF_ERR_INVALID_OBJECT | 控制器对象非法 | + | HDF_ERR_MALLOC_FAIL | 内存分配失败 | + | HDF_ERR_INVALID_PARAM | 参数非法 | + | HDF_ERR_IO | I/O 错误 | + | HDF_SUCCESS | 初始化成功 | + | HDF_FAILURE | 初始化失败 | + + 函数说明: + + 初始化自定义结构体对象,初始化I2sCntlr 成员。 + + ```c + static int32_t HdfI2sDeviceInit(struct HdfDeviceObject *device) + { + struct I2sCntlr *cntlr = NULL; + ... + cntlr = I2sCntlrFromDevice(device); + ... + int32_t ret = I2sInit(cntlr, device); + ... + return ret; + } + ``` + + - Release函数参考 + + 入参: + + HdfDeviceObject 是整个驱动对外暴露的接口参数,具备 HCS 配置文件的信息。 + + 返回值: + + 无。 + + 函数说明: + + 释放内存和删除控制器,该函数需要在驱动入口结构体中赋值给 Release 接口, 当HDF框架调用Init函数初始化驱动失败时,可以调用 Release 释放驱动资源。所有强制转换获取相应对象的操作**前提**是在Init函数中具备对应赋值的操作。 + + ```c + static void HdfI2sDeviceRelease(struct HdfDeviceObject *device) + { + struct I2sCntlr *cntlr = NULL; + ... + cntlr = I2sCntlrFromDevice(device); + ... + if (cntlr->priv != NULL) { + struct I2sConfigInfo *configInfo = cntlr->priv; + if (configInfo->regBase != 0) { + OsalIoUnmap((void *)configInfo->regBase); + } + if (configInfo->codecAddr != 0) { + OsalIoUnmap((void *)configInfo->codecAddr); + } + if (configInfo->crg103Addr != 0) { + OsalIoUnmap((void *)configInfo->crg103Addr); + } + OsalMemFree(cntlr->priv); + } + I2sCntlrDestroy(cntlr);//释放cntlr对象 + } + ``` + +​ + + + diff --git a/zh-cn/device-dev/driver/driver-platform.md b/zh-cn/device-dev/driver/driver-platform.md index 01fc51f6cd1717787c769e2c1f1f79bc7b67d2d3..b26773496a4d08134cbd46d81666533ee7b8fdf4 100644 --- a/zh-cn/device-dev/driver/driver-platform.md +++ b/zh-cn/device-dev/driver/driver-platform.md @@ -25,3 +25,5 @@ - **[UART](driver-platform-uart-des.md)** - **[WATCHDOG](driver-platform-watchdog-des.md)** + +- **[I2S](driver-platform-i2s-des.md)** diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png" new file mode 100755 index 0000000000000000000000000000000000000000..c3684f735f8a68a198c3ced8a243b6674760272d Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257controller.png" differ diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png" new file mode 100755 index 0000000000000000000000000000000000000000..056e2b9178b380023228d9a9747d8fd4f02b14d8 Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257receiver.png" differ diff --git "a/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png" "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png" new file mode 100755 index 0000000000000000000000000000000000000000..889c0c0ba5a11880ea41fdbbd8a00b5c2bd61e5e Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S-master\346\230\257transmiter.png" differ diff --git "a/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png" "b/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png" new file mode 100755 index 0000000000000000000000000000000000000000..92013eb57c9c4c5fa3bbbde4edd109cc441295e0 Binary files /dev/null and "b/zh-cn/device-dev/driver/figures/I2S\344\275\277\347\224\250\346\265\201\347\250\213\345\233\276.png" differ