Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
AdRainty
rt-thread
提交
500b5498
R
rt-thread
项目概览
AdRainty
/
rt-thread
与 Fork 源项目一致
Fork自
RT-Thread / rt-thread
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
rt-thread
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
未验证
提交
500b5498
编写于
12月 09, 2019
作者:
B
Bernard Xiong
提交者:
GitHub
12月 09, 2019
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #3213 from liweihao-cn/master
增加音频设备驱动
上级
cd50a40f
df972149
变更
9
隐藏空白更改
内联
并排
Showing
9 changed file
with
1375 addition
and
2 deletion
+1375
-2
bsp/lpc54114-lite/README.md
bsp/lpc54114-lite/README.md
+2
-2
bsp/lpc54114-lite/drivers/Kconfig
bsp/lpc54114-lite/drivers/Kconfig
+15
-0
bsp/lpc54114-lite/drivers/SConscript
bsp/lpc54114-lite/drivers/SConscript
+10
-0
bsp/lpc54114-lite/drivers/audio/drv_mic.c
bsp/lpc54114-lite/drivers/audio/drv_mic.c
+163
-0
bsp/lpc54114-lite/drivers/audio/drv_mic.h
bsp/lpc54114-lite/drivers/audio/drv_mic.h
+17
-0
bsp/lpc54114-lite/drivers/audio/drv_sound.c
bsp/lpc54114-lite/drivers/audio/drv_sound.c
+361
-0
bsp/lpc54114-lite/drivers/audio/drv_sound.h
bsp/lpc54114-lite/drivers/audio/drv_sound.h
+17
-0
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.c
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.c
+543
-0
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.h
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.h
+247
-0
未找到文件。
bsp/lpc54114-lite/README.md
浏览文件 @
500b5498
...
...
@@ -41,8 +41,8 @@ LPC54114-Lite 开发板的更多详细信息请参考万利电子 [开发板用
| SPI Flash | 支持 |- |
| SPI TF 卡 | 支持 |- |
| I2C 温度传感器
<BR>
(PCT2075DP) | 支持 |- |
| I2S 音频输入 / 输出接口
<BR>
(WM8904) |
暂不支持 |-
|
| PDM 数字麦克风
<BR>
(SPH0641LM4H) |
暂不
支持 |- |
| I2S 音频输入 / 输出接口
<BR>
(WM8904) |
支持 |仅支持解码
|
| PDM 数字麦克风
<BR>
(SPH0641LM4H) | 支持 |- |
|
**片上外设**
|
**支持情况**
|
**备注**
|
| GPIO | 支持 | PIO0_0 ... PIO1_31 ---> PIN: 0, 1...63 |
| UART | 支持 | UART0 |
...
...
bsp/lpc54114-lite/drivers/Kconfig
浏览文件 @
500b5498
...
...
@@ -35,4 +35,19 @@ menu "LPC54110 Bsp Config"
select BSP_USING_SPI2
default y
config BSP_USING_AUDIO
bool "Enable Audio(WM8904&SPH0641LU4H)"
select RT_USING_AUDIO
default n
if BSP_USING_AUDIO
config BSP_USING_AUDIO_REPLAY
bool "Enable WM8904(only replay)"
select BSP_USING_I2C4
default y
config BSP_USING_AUDIO_RECORD
bool "Enable SPH0641LU4H"
default y
endif
endmenu
bsp/lpc54114-lite/drivers/SConscript
浏览文件 @
500b5498
...
...
@@ -29,6 +29,16 @@ if GetDepend('BSP_USING_SDCARD'):
if
GetDepend
(
'BSP_USING_SPIFLASH'
):
src
=
src
+
[
'drv_spi_flash.c'
]
if
GetDepend
(
'BSP_USING_AUDIO_REPLAY'
):
src
=
src
+
[
'audio/drv_sound.c'
]
src
=
src
+
[
'audio/fsl_wm8904.c'
]
if
GetDepend
(
'BSP_USING_AUDIO_RECORD'
):
src
=
src
+
[
'audio/drv_mic.c'
]
if
GetDepend
(
'BSP_USING_AUDIO_REPLAY'
)
or
GetDepend
(
'BSP_USING_AUDIO_RECORD'
):
CPPPATH
+=
[
cwd
+
'audio'
]
group
=
DefineGroup
(
'Drivers'
,
src
,
depend
=
[
''
],
CPPPATH
=
CPPPATH
)
Return
(
'group'
)
bsp/lpc54114-lite/drivers/audio/drv_mic.c
0 → 100644
浏览文件 @
500b5498
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-11-17 LiWeiHao First implementation
*/
#include "drv_mic.h"
#include "fsl_common.h"
#include "fsl_iocon.h"
#include "fsl_dmic.h"
#include "fsl_dma.h"
#include "fsl_dmic_dma.h"
struct
mic_device
{
dma_handle_t
dma_handle
;
dmic_dma_handle_t
dmic_dma_handle
;
struct
rt_audio_device
audio
;
struct
rt_audio_configure
config
;
rt_uint8_t
*
rx_fifo
;
};
#define DMAREQ_DMIC0 16U
#define DMAREQ_DMIC1 17U
#define DMAREQ_CHANNEL DMAREQ_DMIC0
#define DMIC_CHANNEL kDMIC_Channel0
#define DMIC_CHANNEL_ENABLE DMIC_CHANEN_EN_CH0(1)
#define FIFO_DEPTH 15U
#define RX_DMA_FIFO_SIZE (2048)
struct
mic_device
mic_dev
;
void
dmic_dma_transfer_callback
(
DMIC_Type
*
base
,
dmic_dma_handle_t
*
handle
,
status_t
status
,
void
*
userData
)
{
struct
mic_device
*
mic_dev
=
(
struct
mic_device
*
)
userData
;
rt_audio_rx_done
(
&
mic_dev
->
audio
,
&
mic_dev
->
rx_fifo
[
0
],
RX_DMA_FIFO_SIZE
);
dmic_transfer_t
dmic_transfer
;
dmic_transfer
.
data
=
(
uint16_t
*
)
&
mic_dev
->
rx_fifo
[
0
];
dmic_transfer
.
dataSize
=
RX_DMA_FIFO_SIZE
/
2
;
DMIC_TransferReceiveDMA
(
DMIC0
,
&
mic_dev
->
dmic_dma_handle
,
&
dmic_transfer
,
kDMIC_Channel0
);
}
rt_err_t
mic_device_init
(
struct
rt_audio_device
*
audio
)
{
dmic_channel_config_t
dmic_channel_cfg
;
CLOCK_EnableClock
(
kCLOCK_Iocon
);
CLOCK_EnableClock
(
kCLOCK_InputMux
);
CLOCK_EnableClock
(
kCLOCK_Gpio0
);
IOCON_PinMuxSet
(
IOCON
,
1
,
16
,
IOCON_FUNC1
|
IOCON_DIGITAL_EN
);
IOCON_PinMuxSet
(
IOCON
,
1
,
15
,
IOCON_FUNC1
|
IOCON_DIGITAL_EN
);
CLOCK_AttachClk
(
kFRO12M_to_DMIC
);
CLOCK_SetClkDiv
(
kCLOCK_DivDmicClk
,
14
,
false
);
dmic_channel_cfg
.
divhfclk
=
kDMIC_PdmDiv1
;
dmic_channel_cfg
.
osr
=
25U
;
dmic_channel_cfg
.
gainshft
=
2U
;
dmic_channel_cfg
.
preac2coef
=
kDMIC_CompValueZero
;
dmic_channel_cfg
.
preac4coef
=
kDMIC_CompValueZero
;
dmic_channel_cfg
.
dc_cut_level
=
kDMIC_DcCut155
;
dmic_channel_cfg
.
post_dc_gain_reduce
=
1
;
dmic_channel_cfg
.
saturate16bit
=
1U
;
dmic_channel_cfg
.
sample_rate
=
kDMIC_PhyFullSpeed
;
DMIC_Init
(
DMIC0
);
DMIC_ConfigIO
(
DMIC0
,
kDMIC_PdmDual
);
DMIC_Use2fs
(
DMIC0
,
true
);
DMIC_SetOperationMode
(
DMIC0
,
kDMIC_OperationModeDma
);
DMIC_ConfigChannel
(
DMIC0
,
DMIC_CHANNEL
,
kDMIC_Left
,
&
dmic_channel_cfg
);
DMIC_FifoChannel
(
DMIC0
,
DMIC_CHANNEL
,
FIFO_DEPTH
,
true
,
true
);
DMIC_EnableChannnel
(
DMIC0
,
DMIC_CHANNEL_ENABLE
);
DMA_EnableChannel
(
DMA0
,
DMAREQ_CHANNEL
);
/* Request dma channels from DMA manager. */
DMA_CreateHandle
(
&
mic_dev
.
dma_handle
,
DMA0
,
DMAREQ_CHANNEL
);
/* Create DMIC DMA handle. */
DMIC_TransferCreateHandleDMA
(
DMIC0
,
&
mic_dev
.
dmic_dma_handle
,
dmic_dma_transfer_callback
,
(
void
*
)
&
mic_dev
,
&
mic_dev
.
dma_handle
);
return
RT_EOK
;
}
rt_err_t
mic_device_start
(
struct
rt_audio_device
*
audio
,
int
stream
)
{
struct
mic_device
*
mic_dev
=
(
struct
mic_device
*
)
audio
->
parent
.
user_data
;
if
(
stream
==
AUDIO_STREAM_RECORD
)
{
dmic_transfer_t
dmic_transfer
;
dmic_transfer
.
data
=
(
uint16_t
*
)
&
mic_dev
->
rx_fifo
[
0
];
dmic_transfer
.
dataSize
=
RX_DMA_FIFO_SIZE
/
2
;
DMIC_TransferReceiveDMA
(
DMIC0
,
&
mic_dev
->
dmic_dma_handle
,
&
dmic_transfer
,
kDMIC_Channel0
);
}
return
RT_EOK
;
}
rt_err_t
mic_device_stop
(
struct
rt_audio_device
*
audio
,
int
stream
)
{
struct
mic_device
*
mic_dev
=
(
struct
mic_device
*
)
audio
->
parent
.
user_data
;
if
(
stream
==
AUDIO_STREAM_RECORD
)
{
DMIC_TransferAbortReceiveDMA
(
DMIC0
,
&
mic_dev
->
dmic_dma_handle
);
}
return
RT_EOK
;
}
rt_err_t
mic_device_getcaps
(
struct
rt_audio_device
*
audio
,
struct
rt_audio_caps
*
caps
)
{
return
RT_EOK
;
}
rt_err_t
mic_device_configure
(
struct
rt_audio_device
*
audio
,
struct
rt_audio_caps
*
caps
)
{
return
RT_EOK
;
}
static
struct
rt_audio_ops
_mic_audio_ops
=
{
.
getcaps
=
mic_device_getcaps
,
.
configure
=
mic_device_configure
,
.
init
=
mic_device_init
,
.
start
=
mic_device_start
,
.
stop
=
mic_device_stop
,
.
transmit
=
RT_NULL
,
.
buffer_info
=
RT_NULL
,
};
int
rt_hw_mic_init
(
void
)
{
struct
rt_audio_device
*
audio
=
&
mic_dev
.
audio
;
/* mic default */
mic_dev
.
rx_fifo
=
rt_calloc
(
1
,
RX_DMA_FIFO_SIZE
);
if
(
mic_dev
.
rx_fifo
==
RT_NULL
)
{
return
-
RT_ENOMEM
;
}
mic_dev
.
config
.
channels
=
1
;
mic_dev
.
config
.
samplerate
=
16000
;
mic_dev
.
config
.
samplebits
=
16
;
/* register mic device */
audio
->
ops
=
&
_mic_audio_ops
;
rt_audio_register
(
audio
,
"mic0"
,
RT_DEVICE_FLAG_RDONLY
,
(
void
*
)
&
mic_dev
);
return
RT_EOK
;
}
INIT_DEVICE_EXPORT
(
rt_hw_mic_init
);
\ No newline at end of file
bsp/lpc54114-lite/drivers/audio/drv_mic.h
0 → 100644
浏览文件 @
500b5498
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-11-17 LiWeiHao First implementation
*/
#ifndef __DRV_MIC_H__
#define __DRV_MIC_H__
#include <rtthread.h>
#include <rtdevice.h>
#endif
bsp/lpc54114-lite/drivers/audio/drv_sound.c
0 → 100644
浏览文件 @
500b5498
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-11-17 LiWeiHao First implementation
*/
#include "drv_sound.h"
#include "fsl_common.h"
#include "fsl_iocon.h"
#include "fsl_dma.h"
#include "fsl_i2s.h"
#include "fsl_i2s_dma.h"
#include "fsl_wm8904.h"
#include "fsl_i2c.h"
#define TX_FIFO_SIZE (4096)
#define I2S_TX I2S1
#define I2S_RX I2S0
#define I2S_DMA_TX 15
#define I2S_DMA_RX 12
#ifndef CODEC_I2C_NAME
#define CODEC_I2C_NAME "i2c4"
#endif
struct
sound_device
{
wm8904_handle_t
wm8904_handle
;
dma_handle_t
tx_dma_handle
;
i2s_dma_handle_t
tx_i2s_dma_handle
;
struct
rt_audio_device
audio
;
struct
rt_audio_configure
replay_config
;
rt_uint8_t
volume
;
rt_uint8_t
*
tx_fifo
;
};
const
pll_setup_t
pll_setup
=
{
.
syspllctrl
=
SYSCON_SYSPLLCTRL_BANDSEL_MASK
|
SYSCON_SYSPLLCTRL_SELP
(
0x1FU
)
|
SYSCON_SYSPLLCTRL_SELI
(
0x8U
),
.
syspllndec
=
SYSCON_SYSPLLNDEC_NDEC
(
0x2DU
),
.
syspllpdec
=
SYSCON_SYSPLLPDEC_PDEC
(
0x42U
),
.
syspllssctrl
=
{
SYSCON_SYSPLLSSCTRL0_MDEC
(
0x34D3U
)
|
SYSCON_SYSPLLSSCTRL0_SEL_EXT_MASK
,
0x00000000U
},
.
pllRate
=
24576000U
,
/* 16 bits * 2 channels * 44.1 kHz * 16 */
.
flags
=
PLL_SETUPFLAG_WAITLOCK
};
static
struct
sound_device
snd_dev
;
void
i2s_tx_transfer_callback
(
I2S_Type
*
base
,
i2s_dma_handle_t
*
handle
,
status_t
completionStatus
,
void
*
userData
)
{
struct
sound_device
*
snd_dev
=
(
struct
sound_device
*
)
userData
;
rt_audio_tx_complete
(
&
snd_dev
->
audio
);
}
static
rt_err_t
lpc_audio_init
(
struct
rt_audio_device
*
audio
)
{
i2s_config_t
tx_i2s_config
;
wm8904_config_t
wm8904_config
;
CLOCK_EnableClock
(
kCLOCK_Iocon
);
CLOCK_EnableClock
(
kCLOCK_InputMux
);
CLOCK_EnableClock
(
kCLOCK_Gpio0
);
CLOCK_EnableClock
(
kCLOCK_Gpio1
);
CLOCK_AttachClk
(
kFRO12M_to_SYS_PLL
);
CLOCK_AttachClk
(
kSYS_PLL_to_FLEXCOMM7
);
RESET_PeripheralReset
(
kFC7_RST_SHIFT_RSTn
);
CLOCK_SetPLLFreq
(
&
pll_setup
);
CLOCK_AttachClk
(
kSYS_PLL_to_MCLK
);
SYSCON
->
MCLKDIV
=
SYSCON_MCLKDIV_DIV
(
0U
);
// Flexcomm 7 I2S Tx
IOCON_PinMuxSet
(
IOCON
,
1
,
12
,
IOCON_FUNC4
|
IOCON_DIGITAL_EN
);
/* Flexcomm 7 / SCK */
IOCON_PinMuxSet
(
IOCON
,
1
,
13
,
IOCON_FUNC4
|
IOCON_DIGITAL_EN
);
/* Flexcomm 7 / SDA */
IOCON_PinMuxSet
(
IOCON
,
1
,
14
,
IOCON_FUNC4
|
IOCON_DIGITAL_EN
);
/* Flexcomm 7 / WS */
/* MCLK output for I2S */
IOCON_PinMuxSet
(
IOCON
,
1
,
17
,
IOCON_FUNC4
|
IOCON_MODE_INACT
|
IOCON_DIGITAL_EN
);
SYSCON
->
MCLKIO
=
1U
;
WM8904_GetDefaultConfig
(
&
wm8904_config
);
snd_dev
.
wm8904_handle
.
i2c
=
(
struct
rt_i2c_bus_device
*
)
rt_device_find
(
CODEC_I2C_NAME
);
if
(
WM8904_Init
(
&
snd_dev
.
wm8904_handle
,
&
wm8904_config
)
!=
kStatus_Success
)
{
rt_kprintf
(
"wm8904 init failed
\n
"
);
return
-
RT_ERROR
;
}
WM8904_SetMute
(
&
snd_dev
.
wm8904_handle
,
RT_TRUE
,
RT_TRUE
);
I2S_TxGetDefaultConfig
(
&
tx_i2s_config
);
tx_i2s_config
.
divider
=
CLOCK_GetPllOutFreq
()
/
48000U
/
16
/
2
;
I2S_TxInit
(
I2S_TX
,
&
tx_i2s_config
);
DMA_Init
(
DMA0
);
DMA_EnableChannel
(
DMA0
,
I2S_DMA_TX
);
DMA_SetChannelPriority
(
DMA0
,
I2S_DMA_TX
,
kDMA_ChannelPriority3
);
DMA_CreateHandle
(
&
snd_dev
.
tx_dma_handle
,
DMA0
,
I2S_DMA_TX
);
I2S_TxTransferCreateHandleDMA
(
I2S_TX
,
&
snd_dev
.
tx_i2s_dma_handle
,
&
snd_dev
.
tx_dma_handle
,
i2s_tx_transfer_callback
,
(
void
*
)
&
snd_dev
);
return
RT_EOK
;
}
static
rt_err_t
lpc_audio_start
(
struct
rt_audio_device
*
audio
,
int
stream
)
{
RT_ASSERT
(
audio
!=
RT_NULL
);
if
(
stream
==
AUDIO_STREAM_REPLAY
)
{
struct
rt_audio_caps
caps
;
caps
.
main_type
=
AUDIO_TYPE_MIXER
;
caps
.
sub_type
=
AUDIO_MIXER_VOLUME
;
audio
->
ops
->
getcaps
(
audio
,
&
caps
);
audio
->
ops
->
configure
(
audio
,
&
caps
);
rt_audio_tx_complete
(
audio
);
}
return
RT_EOK
;
}
static
rt_err_t
lpc_audio_stop
(
struct
rt_audio_device
*
audio
,
int
stream
)
{
if
(
stream
==
AUDIO_STREAM_REPLAY
)
{
WM8904_SetMute
(
&
snd_dev
.
wm8904_handle
,
RT_TRUE
,
RT_TRUE
);
I2S_TransferAbortDMA
(
I2S_TX
,
&
snd_dev
.
tx_i2s_dma_handle
);
}
return
RT_EOK
;
}
static
rt_err_t
lpc_audio_getcaps
(
struct
rt_audio_device
*
audio
,
struct
rt_audio_caps
*
caps
)
{
rt_err_t
result
=
RT_EOK
;
struct
sound_device
*
snd_dev
;
RT_ASSERT
(
audio
!=
RT_NULL
);
snd_dev
=
(
struct
sound_device
*
)
audio
->
parent
.
user_data
;
switch
(
caps
->
main_type
)
{
case
AUDIO_TYPE_QUERY
:
/* qurey the types of hw_codec device */
{
switch
(
caps
->
sub_type
)
{
case
AUDIO_TYPE_QUERY
:
caps
->
udata
.
mask
=
AUDIO_TYPE_OUTPUT
|
AUDIO_TYPE_MIXER
;
break
;
default:
result
=
-
RT_ERROR
;
break
;
}
break
;
}
case
AUDIO_TYPE_OUTPUT
:
/* Provide capabilities of OUTPUT unit */
{
switch
(
caps
->
sub_type
)
{
case
AUDIO_DSP_PARAM
:
caps
->
udata
.
config
.
samplerate
=
snd_dev
->
replay_config
.
samplerate
;
caps
->
udata
.
config
.
channels
=
snd_dev
->
replay_config
.
channels
;
caps
->
udata
.
config
.
samplebits
=
snd_dev
->
replay_config
.
samplebits
;
break
;
case
AUDIO_DSP_SAMPLERATE
:
caps
->
udata
.
config
.
samplerate
=
snd_dev
->
replay_config
.
samplerate
;
break
;
case
AUDIO_DSP_CHANNELS
:
caps
->
udata
.
config
.
channels
=
snd_dev
->
replay_config
.
channels
;
break
;
case
AUDIO_DSP_SAMPLEBITS
:
caps
->
udata
.
config
.
samplebits
=
snd_dev
->
replay_config
.
samplebits
;
break
;
default:
result
=
-
RT_ERROR
;
break
;
}
break
;
}
case
AUDIO_TYPE_MIXER
:
/* report the Mixer Units */
{
switch
(
caps
->
sub_type
)
{
case
AUDIO_MIXER_QUERY
:
caps
->
udata
.
mask
=
AUDIO_MIXER_VOLUME
;
break
;
case
AUDIO_MIXER_VOLUME
:
caps
->
udata
.
value
=
snd_dev
->
volume
;
break
;
default:
result
=
-
RT_ERROR
;
break
;
}
break
;
}
default:
result
=
-
RT_ERROR
;
break
;
}
return
result
;
}
static
rt_err_t
lpc_audio_configure
(
struct
rt_audio_device
*
audio
,
struct
rt_audio_caps
*
caps
)
{
rt_err_t
result
=
RT_EOK
;
struct
sound_device
*
snd_dev
=
audio
->
parent
.
user_data
;
switch
(
caps
->
main_type
)
{
case
AUDIO_TYPE_MIXER
:
{
switch
(
caps
->
sub_type
)
{
case
AUDIO_MIXER_MUTE
:
{
WM8904_SetMute
(
&
snd_dev
->
wm8904_handle
,
RT_TRUE
,
RT_TRUE
);
snd_dev
->
volume
=
0
;
break
;
}
case
AUDIO_MIXER_VOLUME
:
{
int
volume
=
caps
->
udata
.
value
/
2
;
WM8904_SetMute
(
&
snd_dev
->
wm8904_handle
,
RT_FALSE
,
RT_FALSE
);
WM8904_SetVolume
(
&
snd_dev
->
wm8904_handle
,
volume
,
volume
);
snd_dev
->
volume
=
volume
;
break
;
}
}
break
;
}
case
AUDIO_TYPE_OUTPUT
:
{
switch
(
caps
->
sub_type
)
{
case
AUDIO_DSP_PARAM
:
{
struct
rt_audio_configure
config
=
caps
->
udata
.
config
;
i2s_config_t
tx_i2s_config
;
snd_dev
->
replay_config
.
channels
=
config
.
channels
;
snd_dev
->
replay_config
.
samplebits
=
config
.
samplebits
;
snd_dev
->
replay_config
.
samplerate
=
config
.
samplerate
;
I2S_TxGetDefaultConfig
(
&
tx_i2s_config
);
tx_i2s_config
.
divider
=
CLOCK_GetPllOutFreq
()
/
config
.
samplerate
/
16
/
2
;
I2S_TxInit
(
I2S_TX
,
&
tx_i2s_config
);
break
;
}
case
AUDIO_DSP_SAMPLERATE
:
{
struct
rt_audio_configure
config
=
caps
->
udata
.
config
;
i2s_config_t
tx_i2s_config
;
snd_dev
->
replay_config
.
samplerate
=
config
.
samplerate
;
I2S_TxGetDefaultConfig
(
&
tx_i2s_config
);
tx_i2s_config
.
divider
=
CLOCK_GetPllOutFreq
()
/
config
.
samplerate
/
16
/
2
;
I2S_TxInit
(
I2S_TX
,
&
tx_i2s_config
);
break
;
}
default:
result
=
-
RT_ERROR
;
break
;
}
break
;
}
}
return
result
;
}
static
rt_size_t
lpc_audio_transmit
(
struct
rt_audio_device
*
audio
,
const
void
*
writeBuf
,
void
*
readBuf
,
rt_size_t
size
)
{
RT_ASSERT
(
audio
!=
RT_NULL
);
i2s_transfer_t
transfer
;
transfer
.
data
=
(
uint8_t
*
)
writeBuf
;
transfer
.
dataSize
=
size
;
I2S_TxTransferSendDMA
(
I2S_TX
,
&
snd_dev
.
tx_i2s_dma_handle
,
transfer
);
return
RT_EOK
;
}
static
void
lpc_audio_buffer_info
(
struct
rt_audio_device
*
audio
,
struct
rt_audio_buf_info
*
info
)
{
RT_ASSERT
(
audio
!=
RT_NULL
);
/**
* TX_FIFO
* +----------------+----------------+
* | block1 | block2 |
* +----------------+----------------+
* \ block_size /
*/
info
->
buffer
=
snd_dev
.
tx_fifo
;
info
->
total_size
=
TX_FIFO_SIZE
;
info
->
block_size
=
TX_FIFO_SIZE
/
2
;
info
->
block_count
=
2
;
}
static
struct
rt_audio_ops
audio_ops
=
{
.
getcaps
=
lpc_audio_getcaps
,
.
configure
=
lpc_audio_configure
,
.
init
=
lpc_audio_init
,
.
start
=
lpc_audio_start
,
.
stop
=
lpc_audio_stop
,
.
transmit
=
lpc_audio_transmit
,
.
buffer_info
=
lpc_audio_buffer_info
,
};
int
rt_hw_sound_init
(
void
)
{
rt_uint8_t
*
tx_fifo
=
RT_NULL
;
tx_fifo
=
rt_malloc
(
TX_FIFO_SIZE
);
if
(
tx_fifo
==
NULL
)
{
return
-
RT_ENOMEM
;
}
snd_dev
.
tx_fifo
=
tx_fifo
;
/* init default configuration */
{
snd_dev
.
replay_config
.
samplerate
=
44100
;
snd_dev
.
replay_config
.
channels
=
2
;
snd_dev
.
replay_config
.
samplebits
=
16
;
snd_dev
.
volume
=
30
;
}
snd_dev
.
audio
.
ops
=
&
audio_ops
;
rt_audio_register
(
&
snd_dev
.
audio
,
"sound0"
,
RT_DEVICE_FLAG_WRONLY
,
&
snd_dev
);
return
RT_EOK
;
}
INIT_DEVICE_EXPORT
(
rt_hw_sound_init
);
\ No newline at end of file
bsp/lpc54114-lite/drivers/audio/drv_sound.h
0 → 100644
浏览文件 @
500b5498
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-11-17 LiWeiHao First implementation
*/
#ifndef __DRV_SOUND_H__
#define __DRV_SOUND_H__
#include <rtthread.h>
#include <rtdevice.h>
#endif
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.c
0 → 100755
浏览文件 @
500b5498
/*
* The Clear BSD License
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted (subject to the limitations in the disclaimer below) provided
* that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Change Logs:
* Date Author Notes
* 2019-11-09 LiWeiHao Porting to RT-Thread
*/
#include "fsl_common.h"
#include "fsl_debug_console.h"
#include "fsl_wm8904.h"
#include "fsl_i2c.h"
/*******************************************************************************
* Definitions
******************************************************************************/
#define WM8904_RESET (0x00)
#define WM8904_ANALOG_ADC_0 (0x0A)
#define WM8904_POWER_MGMT_0 (0x0C)
#define WM8904_POWER_MGMT_2 (0x0E)
#define WM8904_POWER_MGMT_6 (0x12)
#define WM8904_CLK_RATES_0 (0x14)
#define WM8904_CLK_RATES_1 (0x15)
#define WM8904_CLK_RATES_2 (0x16)
#define WM8904_AUDIO_IF_0 (0x18)
#define WM8904_AUDIO_IF_1 (0x19)
#define WM8904_AUDIO_IF_2 (0x1A)
#define WM8904_AUDIO_IF_3 (0x1B)
#define WM8904_DAC_DIG_1 (0x21)
#define WM8904_ANALOG_LEFT_IN_0 (0x2C)
#define WM8904_ANALOG_RIGHT_IN_0 (0x2D)
#define WM8904_ANALOG_LEFT_IN_1 (0x2E)
#define WM8904_ANALOG_RIGHT_IN_1 (0x2F)
#define WM8904_ANALOG_OUT1_LEFT (0x39)
#define WM8904_ANALOG_OUT1_RIGHT (0x3A)
#define WM8904_ANALOG_OUT12_ZC (0x3D)
#define WM8904_DC_SERVO_0 (0x43)
#define WM8904_ANALOG_HP_0 (0x5A)
#define WM8904_CHRG_PUMP_0 (0x62)
#define WM8904_CLS_W_0 (0x68)
#define WM8904_WRT_SEQUENCER_0 (0x6C)
#define WM8904_WRT_SEQUENCER_3 (0x6F)
#define WM8904_WRT_SEQUENCER_4 (0x70)
/*******************************************************************************
* Prototypes
******************************************************************************/
static
status_t
WM8904_WaitOnWriteSequencer
(
wm8904_handle_t
*
handle
);
static
status_t
WM8904_WriteRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
value
);
static
status_t
WM8904_ReadRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
*
value
);
static
status_t
WM8904_ModifyRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
mask
,
uint16_t
value
);
/*******************************************************************************
* Variables
******************************************************************************/
static
const
uint8_t
allRegisters
[]
=
{
0x00
,
0x04
,
0x05
,
0x06
,
0x07
,
0x0A
,
0x0C
,
0x0E
,
0x0F
,
0x12
,
0x14
,
0x15
,
0x16
,
0x18
,
0x19
,
0x1A
,
0x1B
,
0x1E
,
0x1F
,
0x20
,
0x21
,
0x24
,
0x25
,
0x26
,
0x27
,
0x28
,
0x29
,
0x2A
,
0x2B
,
0x2C
,
0x2D
,
0x2E
,
0x2F
,
0x39
,
0x3A
,
0x3B
,
0x3C
,
0x3D
,
0x43
,
0x44
,
0x45
,
0x47
,
0x48
,
0x49
,
0x4A
,
0x4B
,
0x4C
,
0x4D
,
0x5A
,
0x5E
,
0x62
,
0x68
,
0x6C
,
0x6D
,
0x6E
,
0x6F
,
0x70
,
0x74
,
0x75
,
0x76
,
0x77
,
0x78
,
0x79
,
0x7A
,
0x7B
,
0x7C
,
0x7E
,
0x7F
,
0x80
,
0x81
,
0x82
,
0x86
,
0x87
,
0x88
,
0x89
,
0x8A
,
0x8B
,
0x8C
,
0x8D
,
0x8E
,
0x8F
,
0x90
,
0x91
,
0x92
,
0x93
,
0x94
,
0x95
,
0x96
,
0x97
,
0x98
,
0x99
,
0x9A
,
0x9B
,
0x9C
,
0x9D
,
0xC6
,
0xF7
,
0xF8
};
/*******************************************************************************
* Code
******************************************************************************/
status_t
WM8904_Init
(
wm8904_handle_t
*
handle
,
wm8904_config_t
*
config
)
{
status_t
result
;
/* reset */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_RESET
,
0x0000
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* MCLK_INV=0, SYSCLK_SRC=0, TOCLK_RATE=0, OPCLK_ENA=1,
* CLK_SYS_ENA=1, CLK_DSP_ENA=1, TOCLK_ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_2
,
0x000F
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* WSEQ_ENA=1, WSEQ_WRITE_INDEX=0_0000 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_WRT_SEQUENCER_0
,
0x0100
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* WSEQ_ABORT=0, WSEQ_START=1, WSEQ_START_INDEX=00_0000 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_WRT_SEQUENCER_3
,
0x0100
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_WaitOnWriteSequencer
(
handle
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* TOCLK_RATE_DIV16=0, TOCLK_RATE_x4=1, SR_MODE=0, MCLK_DIV=1
* (Required for MMCs: SGY, KRT see erratum CE000546) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_0
,
0xA45F
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* INL_ENA=1, INR ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_POWER_MGMT_0
,
0x0003
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* HPL_PGA_ENA=1, HPR_PGA_ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_POWER_MGMT_2
,
0x0003
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* DACL_ENA=1, DACR_ENA=1, ADCL_ENA=1, ADCR_ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_POWER_MGMT_6
,
0x000F
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* ADC_OSR128=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_ADC_0
,
0x0001
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* CLK_SYS_RAT=0101 (512/fs) SAMPLE_RATE=101 (44.1kHz /48kHz) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_1
,
0x1405
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* DACL_DATINV=0, DACR_DATINV=0, DAC_BOOST=00, LOOPBACK=0, AIFADCL_SRC=0,
* AIFADCR_SRC=1, AIFDACL_SRC=0, AIFDACR_SRC=1, ADC_COMP=0, ADC_COMPMODE=0,
* DAC_COMP=0, DAC_COMPMODE=0 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_AUDIO_IF_0
,
0x0050
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* BCLK_DIR=0 (input), AIF_WL=00 (16-bits) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_AUDIO_IF_1
,
0x0002
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* OPCLK_DIV=0 (sysclk), BCLK_DIV=0c (sysclk/16) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_AUDIO_IF_2
,
0x000c
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* LRCLK_DIR=0 (input), LRCLK_RATE=0010_0000_0000 (BCLK / 32) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_AUDIO_IF_3
,
0x0020
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* DAC_MONO=0, DAC_SB_FILT-0, DAC_MUTERATE=0, DAC_UNMUTE RAMP=0,
* DAC_OSR128=1, DAC_MUTE=0, DEEMPH=0 (none) */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_DAC_DIG_1
,
0x0040
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* INL_CM_ENA=0, L_IP_SEL_N=10, L_IP_SEL_P=01, L_MODE=00 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_LEFT_IN_1
,
0x0014
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* INR CM_ENA=0, R_IP_SEL_N=10, R_IP_SEL_P=01, R_MODE=00 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_RIGHT_IN_1
,
0x0014
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* LINMUTE=0, LIN_VOL=0_0101 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_LEFT_IN_0
,
0x0005
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* RINMUTE=0, RIN VOL=0_0101 LINEOUTL RMV SHORT-1, LINEOUTL ENA_OUTP=1,
* LINEOUTL_ENA_DLY=1, LINEOUTL_ENA=1, LINEOUTR_RMV_SHORT-1,
* LINEOUTR_ENA_OUTP=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_RIGHT_IN_0
,
0x0005
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* HPL_BYP_ENA=0, HPR_BYP_ENA=0, LINEOUTL_BYP ENA=0, LINEOUTR_BYP ENA=0 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_OUT12_ZC
,
0x0000
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* HPOUTL_MUTE=0, HPOUT_VU=0, HPOUTLZC=0, HPOUTL_VOL=11_1001 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_OUT1_LEFT
,
0x0039
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* HPOUTR_MUTE=0, HPOUT_VU=0, HPOUTRZC=0, HPOUTR_VOL=11_1001 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_OUT1_RIGHT
,
0x0039
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* Enable DC servos for headphone out */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_DC_SERVO_0
,
0x0003
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* HPL_RMV_SHORT=1, HPL_ENA_OUTP=1, HPL_ENA_DLY=1, HPL_ENA=1,
* HPR_RMV_SHORT=1, HPR_ENA_OUTP=1, HPR_ENA_DLY=1, HPR_ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_ANALOG_HP_0
,
0x00FF
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* CP_DYN_PWR=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLS_W_0
,
0x0001
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* CP_ENA=1 */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CHRG_PUMP_0
,
0x0001
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_SetMasterSlave
(
handle
,
config
->
master
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_SetProtocol
(
handle
,
config
->
protocol
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_SetAudioFormat
(
handle
,
&
(
config
->
format
));
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
return
kStatus_WM8904_Success
;
}
status_t
WM8904_Deinit
(
wm8904_handle_t
*
handle
)
{
/* reset */
return
WM8904_WriteRegister
(
handle
,
WM8904_RESET
,
0x0000
);
}
void
WM8904_GetDefaultConfig
(
wm8904_config_t
*
config
)
{
memset
(
config
,
0
,
sizeof
(
wm8904_config_t
));
config
->
master
=
false
;
config
->
protocol
=
kWM8904_ProtocolI2S
;
config
->
format
.
fsRatio
=
kWM8904_FsRatio64X
;
config
->
format
.
sampleRate
=
kWM8904_SampleRate48kHz
;
config
->
format
.
bitWidth
=
kWM8904_BitWidth16
;
}
status_t
WM8904_SetMasterSlave
(
wm8904_handle_t
*
handle
,
bool
master
)
{
if
(
master
)
{
/* only slave currently supported */
return
kStatus_WM8904_Fail
;
}
return
kStatus_WM8904_Success
;
}
status_t
WM8904_SetProtocol
(
wm8904_handle_t
*
handle
,
wm8904_protocol_t
protocol
)
{
return
WM8904_ModifyRegister
(
handle
,
WM8904_AUDIO_IF_1
,
0x0003
,
(
uint16_t
)
protocol
);
}
status_t
WM8904_SetAudioFormat
(
wm8904_handle_t
*
handle
,
wm8904_audio_format_t
*
format
)
{
status_t
result
;
/* Disable SYSCLK */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_2
,
0x00
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* Set Clock ratio and sample rate */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_1
,
((
uint32_t
)
format
->
fsRatio
<<
10
)
|
format
->
sampleRate
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* Set bit resolution */
result
=
WM8904_ModifyRegister
(
handle
,
WM8904_AUDIO_IF_1
,
0x000C
,
(
uint16_t
)
format
->
bitWidth
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
/* Enable SYSCLK */
result
=
WM8904_WriteRegister
(
handle
,
WM8904_CLK_RATES_2
,
0x1007
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
return
kStatus_WM8904_Success
;
}
status_t
WM8904_SetVolume
(
wm8904_handle_t
*
handle
,
uint16_t
volumeLeft
,
uint16_t
volumeRight
)
{
status_t
result
;
result
=
WM8904_ModifyRegister
(
handle
,
WM8904_ANALOG_OUT1_LEFT
,
0x3F
,
volumeLeft
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_ModifyRegister
(
handle
,
WM8904_ANALOG_OUT1_RIGHT
,
0xBF
,
volumeRight
|
0x0080
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
return
kStatus_WM8904_Success
;
}
status_t
WM8904_SetMute
(
wm8904_handle_t
*
handle
,
bool
muteLeft
,
bool
muteRight
)
{
status_t
result
;
uint16_t
left
=
muteLeft
?
0x0100
:
0x0000
;
uint16_t
right
=
muteRight
?
0x0100
:
0x0000
;
result
=
WM8904_ModifyRegister
(
handle
,
WM8904_ANALOG_OUT1_LEFT
,
0x0100
,
left
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
result
=
WM8904_ModifyRegister
(
handle
,
WM8904_ANALOG_OUT1_RIGHT
,
0x0180
,
right
|
0x0080
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
return
kStatus_WM8904_Success
;
}
status_t
WM8904_PrintRegisters
(
wm8904_handle_t
*
handle
)
{
status_t
result
;
uint16_t
value
;
uint32_t
i
;
for
(
i
=
0
;
i
<
sizeof
(
allRegisters
);
i
++
)
{
result
=
WM8904_ReadRegister
(
handle
,
allRegisters
[
i
],
&
value
);
if
(
result
!=
kStatus_WM8904_Success
)
{
PRINTF
(
"
\r\n
"
);
return
result
;
}
PRINTF
(
"%s"
,
((
i
%
8
)
==
0
)
?
"
\r\n
"
:
"
\t
"
);
PRINTF
(
"%02X:%04X"
,
allRegisters
[
i
],
value
);
}
PRINTF
(
"
\r\n
"
);
return
result
;
}
static
status_t
WM8904_WaitOnWriteSequencer
(
wm8904_handle_t
*
handle
)
{
status_t
result
;
uint16_t
value
;
do
{
result
=
WM8904_ReadRegister
(
handle
,
WM8904_WRT_SEQUENCER_4
,
&
value
);
}
while
((
result
==
kStatus_WM8904_Success
)
&&
(
value
&
1
));
return
result
;
}
static
status_t
WM8904_WriteRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
value
)
{
rt_size_t
result
;
struct
rt_i2c_msg
msgs
;
uint8_t
buffer
[
3
];
buffer
[
0
]
=
reg
;
buffer
[
1
]
=
(
value
>>
8U
)
&
0xFFU
;
buffer
[
2
]
=
value
&
0xFFU
;
msgs
.
addr
=
WM8904_I2C_ADDRESS
;
msgs
.
flags
=
RT_I2C_WR
;
msgs
.
buf
=
buffer
;
msgs
.
len
=
sizeof
(
buffer
);
result
=
rt_i2c_transfer
(
handle
->
i2c
,
&
msgs
,
1
);
if
(
result
==
1
)
{
return
kStatus_WM8904_Success
;
}
else
{
return
kStatus_WM8904_Fail
;
}
}
static
status_t
WM8904_ReadRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
*
value
)
{
rt_size_t
result
;
struct
rt_i2c_msg
msgs
[
2
];
uint8_t
buffer
[
2
]
=
{
0
};
uint8_t
write_buffer
;
*
value
=
0x0000U
;
write_buffer
=
reg
;
msgs
[
0
].
addr
=
WM8904_I2C_ADDRESS
;
msgs
[
0
].
flags
=
RT_I2C_WR
;
msgs
[
0
].
buf
=
&
write_buffer
;
msgs
[
0
].
len
=
1
;
msgs
[
1
].
addr
=
WM8904_I2C_ADDRESS
;
msgs
[
1
].
flags
=
RT_I2C_RD
;
msgs
[
1
].
buf
=
buffer
;
msgs
[
1
].
len
=
2
;
result
=
rt_i2c_transfer
(
handle
->
i2c
,
msgs
,
2
);
if
(
result
!=
2
)
{
return
kStatus_WM8904_Fail
;
}
*
value
=
(
uint16_t
)((((
uint32_t
)
buffer
[
0
])
<<
8U
)
|
((
uint32_t
)
buffer
[
1
]));
return
kStatus_WM8904_Success
;
}
static
status_t
WM8904_ModifyRegister
(
wm8904_handle_t
*
handle
,
uint8_t
reg
,
uint16_t
mask
,
uint16_t
value
)
{
status_t
result
;
uint16_t
regValue
;
result
=
WM8904_ReadRegister
(
handle
,
reg
,
&
regValue
);
if
(
result
!=
kStatus_WM8904_Success
)
{
return
result
;
}
regValue
&=
(
uint16_t
)
~
mask
;
regValue
|=
value
;
return
WM8904_WriteRegister
(
handle
,
reg
,
regValue
);
}
bsp/lpc54114-lite/drivers/audio/fsl_wm8904.h
0 → 100755
浏览文件 @
500b5498
/*
* The Clear BSD License
* Copyright (c) 2016, Freescale Semiconductor, Inc.
* Copyright 2016-2017 NXP
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted (subject to the limitations in the disclaimer below) provided
* that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice, this list
* of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice, this
* list of conditions and the following disclaimer in the documentation and/or
* other materials provided with the distribution.
*
* o Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE GRANTED BY THIS LICENSE.
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Change Logs:
* Date Author Notes
* 2019-11-09 LiWeiHao Porting to RT-Thread
*/
#ifndef _FSL_WM8904_H_
#define _FSL_WM8904_H_
#include "fsl_common.h"
#include "rtdevice.h"
#include "rtthread.h"
/*!
* @addtogroup wm8904
* @{
*/
/*******************************************************************************
* Definitions
******************************************************************************/
/*! @brief WM8904 I2C address. */
#define WM8904_I2C_ADDRESS (0x1A)
/*! @brief WM8904 I2C bit rate. */
#define WM8904_I2C_BITRATE (400000U)
/*! @brief WM8904 status return codes. */
enum
_wm8904_status
{
kStatus_WM8904_Success
=
0x0
,
/*!< Success */
kStatus_WM8904_Fail
=
0x1
/*!< Failure */
};
/*! @brief The audio data transfer protocol. */
typedef
enum
_wm8904_protocol
{
kWM8904_ProtocolRightJustified
=
0x0
,
/*!< Right justified mode */
kWM8904_ProtocolLeftJustified
=
0x1
,
/*!< Left justified mode */
kWM8904_ProtocolI2S
=
0x2
,
/*!< I2S mode */
kWM8904_ProtocolDSP
=
0x3
/*!< DSP mode */
}
wm8904_protocol_t
;
/*! @brief The SYSCLK / fs ratio. */
typedef
enum
_wm8904_fs_ratio
{
kWM8904_FsRatio64X
=
0x0
,
/*!< SYSCLK is 64 * sample rate * frame width */
kWM8904_FsRatio128X
=
0x1
,
/*!< SYSCLK is 128 * sample rate * frame width */
kWM8904_FsRatio192X
=
0x2
,
/*!< SYSCLK is 192 * sample rate * frame width */
kWM8904_FsRatio256X
=
0x3
,
/*!< SYSCLK is 256 * sample rate * frame width */
kWM8904_FsRatio384X
=
0x4
,
/*!< SYSCLK is 384 * sample rate * frame width */
kWM8904_FsRatio512X
=
0x5
,
/*!< SYSCLK is 512 * sample rate * frame width */
kWM8904_FsRatio768X
=
0x6
,
/*!< SYSCLK is 768 * sample rate * frame width */
kWM8904_FsRatio1024X
=
0x7
,
/*!< SYSCLK is 1024 * sample rate * frame width */
kWM8904_FsRatio1408X
=
0x8
,
/*!< SYSCLK is 1408 * sample rate * frame width */
kWM8904_FsRatio1536X
=
0x9
/*!< SYSCLK is 1536 * sample rate * frame width */
}
wm8904_fs_ratio_t
;
/*! @brief Sample rate. */
typedef
enum
_wm8904_sample_rate
{
kWM8904_SampleRate8kHz
=
0x0
,
/*!< 8 kHz */
kWM8904_SampleRate12kHz
=
0x1
,
/*!< 11.025kHz, 12kHz */
kWM8904_SampleRate16kHz
=
0x2
,
/*!< 16kHz */
kWM8904_SampleRate24kHz
=
0x3
,
/*!< 22.05kHz, 24kHz */
kWM8904_SampleRate32kHz
=
0x4
,
/*!< 32kHz */
kWM8904_SampleRate48kHz
=
0x5
/*!< 44.1kHz, 48kHz */
}
wm8904_sample_rate_t
;
/*! @brief Bit width. */
typedef
enum
_wm8904_bit_width
{
kWM8904_BitWidth16
=
0x0
,
/*!< 16 bits */
kWM8904_BitWidth20
=
0x1
,
/*!< 20 bits */
kWM8904_BitWidth24
=
0x2
,
/*!< 24 bits */
kWM8904_BitWidth32
=
0x3
/*!< 32 bits */
}
wm8904_bit_width_t
;
/*! @brief Audio format configuration. */
typedef
struct
_wm8904_audio_format
{
wm8904_fs_ratio_t
fsRatio
;
/*!< SYSCLK / fs ratio */
wm8904_sample_rate_t
sampleRate
;
/*!< Sample rate */
wm8904_bit_width_t
bitWidth
;
/*!< Bit width */
}
wm8904_audio_format_t
;
/*! @brief WM8904 data. */
typedef
struct
_wm8904_handle
{
struct
rt_i2c_bus_device
*
i2c
;
/*!< Configured I2C instance */
}
wm8904_handle_t
;
/*! @brief Configuration structure of WM8904. */
typedef
struct
_wm8904_config
{
bool
master
;
/*!< Master or slave */
wm8904_protocol_t
protocol
;
/*!< Audio transfer protocol */
wm8904_audio_format_t
format
;
/*!< Audio format */
}
wm8904_config_t
;
/*******************************************************************************
* API
******************************************************************************/
#if defined(__cplusplus)
extern
"C"
{
#endif
/*!
* @brief Initializes WM8904.
*
* @param handle WM8904 handle structure.
* @param codec_config WM8904 configuration structure.
*/
status_t
WM8904_Init
(
wm8904_handle_t
*
handle
,
wm8904_config_t
*
config
);
/*!
* @brief Deinitializes the WM8904 codec.
*
* This function resets WM8904.
*
* @param handle WM8904 handle structure.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_Deinit
(
wm8904_handle_t
*
handle
);
/*!
* @brief Fills the configuration structure with default values.
*
* The default values are:
*
* master = false;
* protocol = kWM8904_ProtocolI2S;
* format.fsRatio = kWM8904_FsRatio64X;
* format.sampleRate = kWM8904_SampleRate48kHz;
* format.bitWidth = kWM8904_BitWidth16;
*
* @param handle WM8904 handle structure to be filled with default values.
*/
void
WM8904_GetDefaultConfig
(
wm8904_config_t
*
config
);
/*!
* @brief Sets WM8904 as master or slave.
*
* @param handle WM8904 handle structure.
* @param master true for master, false for slave.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_SetMasterSlave
(
wm8904_handle_t
*
handle
,
bool
master
);
/*!
* @brief Sets the audio data transfer protocol.
*
* @param handle WM8904 handle structure.
* @param protocol Audio transfer protocol.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_SetProtocol
(
wm8904_handle_t
*
handle
,
wm8904_protocol_t
protocol
);
/*!
* @brief Sets the audio data format.
*
* @param handle WM8904 handle structure.
* @param format Audio format parameters.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_SetAudioFormat
(
wm8904_handle_t
*
handle
,
wm8904_audio_format_t
*
format
);
/*!
* @brief Sets the headphone output volume.
*
* The parameter should be from 0 to 63.
* The resulting volume will be (parameter - 57 dB).
* 0 for -57 dB, 57 for 0 dB, 63 for +6 dB etc.
*
* @param handle WM8904 handle structure.
* @param volumeLeft Volume of the left channel.
* @param volumeRight Volume of the right channel.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_SetVolume
(
wm8904_handle_t
*
handle
,
uint16_t
volumeLeft
,
uint16_t
volumeRight
);
/*!
* @brief Sets the headphone output mute.
*
* @param handle WM8904 handle structure.
* @param muteLeft true to mute left channel, false to unmute.
* @param muteRight true to mute right channel, false to unmute.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_SetMute
(
wm8904_handle_t
*
handle
,
bool
muteLeft
,
bool
muteRight
);
/*!
* @brief Reads content of all WM8904 registers and prints it to debug console.
*
* @param handle WM8904 handle structure.
*
* @return kStatus_WM8904_Success if successful, different code otherwise.
*/
status_t
WM8904_PrintRegisters
(
wm8904_handle_t
*
handle
);
#if defined(__cplusplus)
}
#endif
/*! @} */
#endif
/* _FSL_WM8904_H_ */
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录