component/bt: A2DP code original in example project moved to component/bt directory;

1. move btif and A2DP source code from project directory to bluetooth directory;
2. some updates of audio source code;
This commit is contained in:
wangmengyang 2016-12-26 17:40:28 +08:00
parent 6163d214b3
commit 0ad3017df7
132 changed files with 222955 additions and 39 deletions

View file

@ -29,4 +29,5 @@ typedef enum {
esp_err_t esp_bt_gap_set_scan_mode(bt_scan_mode_t mode);
esp_err_t esp_bt_gap_set_device_name(const char *name);
#endif /* __ESP_GAP_BT_API_H__ */

View file

@ -10,6 +10,7 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
bluedroid/hci/include \
bluedroid/osi/include \
bluedroid/utils/include \
bluedroid/embdrv/sbc/decoder/include \
bluedroid/btc/core/include \
bluedroid/btc/profile/esp/blufi/include \
bluedroid/btc/profile/esp/include \
@ -18,6 +19,7 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
bluedroid/btc/profile/std/sdp/include \
bluedroid/btc/profile/std/include \
bluedroid/btc/include \
bluedroid/btif/include \
bluedroid/stack/btm/include \
bluedroid/stack/btu/include \
bluedroid/stack/gap/include \
@ -32,7 +34,7 @@ COMPONENT_ADD_INCLUDEDIRS := bluedroid/bta/include \
bluedroid/stack/a2dp/include \
bluedroid/stack/include \
bluedroid/utils/include \
bluedroid/api/include \
bluedroid/api/include \
bluedroid/include \
include
@ -59,6 +61,7 @@ COMPONENT_SRCDIRS := bluedroid/bta/dm \
bluedroid/hci \
bluedroid/main \
bluedroid/osi \
bluedroid/embdrv/sbc/decoder/srce \
bluedroid/btc/core \
bluedroid/btc/profile/esp/blufi \
bluedroid/btc/profile/std/gap \

View file

@ -0,0 +1 @@
*.o

View file

@ -0,0 +1,30 @@
menu "EspAudio"
config AUDIO_PLAYER_EN
bool "Enable ESP player"
default y
config AUDIO_RECORDER_EN
bool "Enable ESP recorder"
default y
config AUDIO_LOG_ERROR_EN
bool "Enable Audio error message"
default y
help
Disable it will redurce error information and run faster
config AUDIO_LOG_WARN_EN
bool "Enable Audio warning message"
default y
help
Disable it will redurce warning information and run faster
config AUDIO_LOG_INFO_EN
bool "Enable Audio normal message"
default y
help
Disable it will redurce normal information and run faster
config AUDIO_LOG_DEBUG_EN
bool "Enable Audio debug message"
default n
help
Disable it will redurce debug information and run faster
endmenu

View file

@ -0,0 +1,4 @@
#This is Espressif Audio Platform
# Setting Up ESP-IDF

View file

@ -0,0 +1,17 @@
#
# Component Makefile
#
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := include player/inc recorder/inc \
../media_hal/include \
../misc/include
COMPONENT_SRCDIRS := player recorder
include $(IDF_PATH)/make/component_common.mk

View file

@ -0,0 +1,146 @@
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef ESP_AUDIO
#define ESP_AUDIO
#include "esp_types.h"
#include "EspAudioCom.h"
/*
* Maximum size of the URI, including null character.
*/
//#define MAX_URI_SIZE 1024
/*
* Defines various states that the ESP player can be.
*/
enum EspAudioState
{
AUDIOSTATE_UNINITIALIZED = 0, /* player is not initialized */
AUDIOSTATE_IDLE, /* player is idle */
AUDIOSTATE_STOPPED, /* player is stopled */
AUDIOSTATE_TRANSIT, /* player is busy in a transition */
AUDIOSTATE_PLAYING, /* player is currently playing */
AUDIOSTATE_PAUSED, /* player is in the paused state for playback */
AUDIOSTATE_ENDED, /* player finished decoding player, without user request. */
AUDIOSTATE_ERROR, /* player was given a URI that could not be played */
AUDIOSTATE_UNKNOWN /* unknown playstate */
};
typedef enum
{
InputSrcType_NetSpec = 0, ///< Specify audio file from internet.
InputSrcType_NetLiving = 1, ///< Living audio stream from internet,e.g.m3u8
InputSrcType_LocalFile = 2, ///< Local file which store in the SD card
InputSrcType_Stream = 3, ///< Only audio stream,e.g.PCM
InputSrcType_Max
} InputSrcType;
typedef enum
{
EspAudioErr_NoErr =0, ///< No error
EspAudioErr_InvalidPara, ///< Invalid parameters
EspAudioErr_NoMem, ///< Malloc failed
EspAudioErr_HardwareErr, ///< Hardware error
EspAudioErr_OutOfRange, ///< length of URI is too long.
EspAudioErr_NotSupport, ///< Not support the
} EspAudioErr;
/*
* Initializes the ESP player library.
*/
void EspAudio_Init(void);
/*
* Cleans up the ESP player library.
*/
void EspAudio_UnInit(void);
/*
* Play, stop, pause the streaming and output of player
* EspAudio_Init must be called before these methods work.
*/
int EspAudio_SetupStream(const char* URI, InputSrcType UriType);
/*
* Call this method to transition to playing state.
*
* Returns nonzero if an error occurred.
*/
int EspAudio_Play(void);
/*
* Call this method to stop playing ESP player.
*
* Returns nonzero if an error occurred.
*/
int EspAudio_Stop(void);
/*
* Call this method to pause the playing ESP player.
*
* Returns nonzero if an error occurred.
*/
int EspAudio_Pause(void);
/*
* Returns the playstate of the ESP player library.
* Returns MEDIA_UNKNOWN if the stream could not be found.
*/
enum EspAudioState EspAudio_GetPlayState(void);
/*
* Get the player volume level . Volume level is from 0 to 100.
* Returns a negative value if the stream could not be found or the value is unknown.
*/
int EspAudio_GetVolume(int *level);
/*
* Set the player volume level . Volume level is from 0 to 100.
* Returns a negative value if the stream could not be found or the value is unknown.
*/
int EspAudio_SetVolume(int level);
/*
* Call this method to configrate stream information.
*
* Returns nonzero if an error occurred.
*/
EspAudioErr EspAudioPlayerStreamCfg(uint32_t rate, uint32_t channel,uint32_t bitLen);
/*
* Call this method to flush stream data to driver.
*
* Returns nonzero if an error occurred.
*
* Note:Timeout portMAX_DELAY-block; others,unblock.
*/
EspAudioErr EspAudioPlayerStreamWrite(uint8_t *inData, uint32_t inSize, uint32_t timeout);
/*
* Call this method to stop once stream write.
*
* Returns nonzero if an error occurred.
*
*/
EspAudioErr EspAudioPlayerStreamWriteEnd(void);
#endif

View file

@ -0,0 +1,78 @@
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESPAUDIOCOM_H
#define _ESPAUDIOCOM_H
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "audio_log.h"
#include "EspAudioCom.h"
#define ESP_AUDIO_RELEASE_MAJOR (0000)
#define ESP_AUDIO_RELEASE_MINOR (52)
#define ESP_AUDIO_RELEASE_VER "0.52"
// Specified audio buffer address
#define AUDIO_BUFFER_ADDR (0x3f800000) // For external RAM
// Specified aduio buffer size
#ifdef AUDIO_BUFFER_ADDR
#define AUDIO_BUFFER_SIZE (1024*1024)
#else
#define AUDIO_BUFFER_SIZE (25000)
#endif
typedef struct
{
uint32_t type;
char str[1024];
} UrlInfo;
typedef enum {
StreamType_Opus,
StreamType_Pcm, // it will be support
StreamType_Max,
} StreamType;
typedef enum {
StreamSampleRate_8k = 8000,
StreamSampleRate_16k = 16000, // This is support
StreamSampleRate_22K = 22050,
StreamSampleRate_32K = 32000,
StreamSampleRate_44k = 44100,
StreamSampleRate_48k = 48000,
StreamSampleRate_Max,
} StreamSampleRate;
typedef enum {
StreamBitLen_8BIT = 8,
StreamBitLen_16BIT = 16,
StreamBitLen_24BIT = 24,
StreamBitLen_32BIT = 32,
StreamBitLen_Max,
} StreamBitLen;
typedef enum {
StreamChannel_One, // it will be support
StreamChannel_Two,
StreamChannel_Max,
} StreamChannel;
#endif /* _ESPAUDIOCOM_H */

View file

@ -0,0 +1,70 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef __ESPAUDIORECORDER_H__
#define __ESPAUDIORECORDER_H__
#include "esp_types.h"
#include "EspAudio.h"
//Type Definitions
typedef void (*Callback_RecordData)(void *recBuf, uint32_t *recLen);
typedef enum {
RecorderState_Unknown = 0,
RecorderState_Init,
RecorderState_Stoped,
RecorderState_Recording,
RecorderState_Paused,
} RecorderState;
typedef enum {
EncodeType_Opus = 1,
EncodeType_Pcm,
EncodeType_Max,
} EncodeType;
typedef enum {
RecorderSampleRate_8k = 8000, // it will be support
RecorderSampleRate_16k = 16000,
RecorderSampleRate_Max,
} RecorderSampleRate;
typedef enum {
RecorderChannel_One = 1,
RecorderChannel_Two, // it will be support
RecorderChannel_Max,
} RecorderChannel;
typedef struct {
RecorderSampleRate rate;
RecorderChannel channel;
EncodeType encodeType;
Callback_RecordData func;
} RecorderAttr;
EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr);
EspAudioErr EspAudioRecorderStop(void);
EspAudioErr EspAudioRecorderPause(void);
EspAudioErr EspAudioRecorderResume(void);
EspAudioErr EspAudioRecorderStateGet(RecorderState *state);
EspAudioErr EspAudioRecorderInit(void);
EspAudioErr EspAudioRecorderUninit(void);
#endif //__ESPAUDIORECORDER_H__

View file

@ -0,0 +1,855 @@
#include <string.h>
#include "esp_types.h"
#include "stdlib.h"
#include "stdio.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "lwip/sockets.h"
#include "lwip/err.h"
#include "lwip/dns.h"
#include "lwip/netdb.h"
#include "lwip/sys.h"
#include "errno.h"
#include "audio_log.h"
#include "inc/DownloadTask.h"
#include "inc/M3u8.h"
#include "EspAudioCom.h"
#include "EspAudio.h"
#include "inc/MediaDecoderTask.h"
#include "Storage.h"
#include "MediaHal.h"
#include "Utility.h"
#define PRIO_DOWNLOAD 19
#define DEFAULT_AAC_SEQ 0xFFFFFFFF
#define REQUEST_BUF_LEN 1024
#define RECV_BUF_LEN 1500
#if 1
#define DEBUGHTTP printf
#else
#define DEBUGHTTP
#endif
uint32_t fileTaskState = 0;
uint32_t m3u8TaskState = 0;
void m3u8DownloadTask(void *pvParameters);
void fileDownloadTask(void *pvParameters);
typedef struct {
int status; // 1:downloading; 2:finished
char *reqBuf;
char *recvBuf;
int blockQuit;
int receivedSize;
uint32_t remaindSize;
uint32_t downloadedSize;
uint32_t contentTotalSize;
UriSrcAttr uri;
} HttpObj;
typedef struct {
TaskState state;
pthread_t thread;
int threadQuit;
} DownloadInstance;
static HttpObj localHttp;
//static mutex_t downloadMutex;
static UrlInfo actLiveUrl;
DownloadInstance dlInstance = { 0 };
typedef void (*Callback_Recv)(HttpObj *obj);
int checkIsReqOk(char *buf)
{
char *l = strstr(buf, "HTTP/1.1 2");
if (NULL == l) {
l = strstr(buf, "HTTP/1.0 2");
if (NULL == l) {
l = strstr(buf, "HTTP/1.0 3");
if (NULL == l) {
return -1;
}
return 1;
}
}
return 0;
}
int getLocation (const char *buf, char* dest)
{
// Location: http://119.90.25.49/live.xmcdn.com/192.168.3.134/live/38/24/161118_174054_588.aac
char *l = strstr(buf, "Location:");
if (NULL == l) {
LOGE("Can't find Location:%s", buf);
return -1;
}
l += 10;
int i1 = 0;
if (l != NULL) {
while (*l != '\r') {
dest[i1++] = *(l++);
if (i1 > ESP_URI_LEN) {
break;
}
}
} else {
LOGE("Can't find Location:%s", buf);
return -1;
}
return 0;
}
int getFileLength(char *buf)
{
char *l = strstr(buf, "Content-Length:");
if (NULL == l) {
LOGE("Can't find length:%s", buf);
return 0;
}
l += 16;
char len[32] = {0};
int i1 = 0;
if (l != NULL) {
while (*l != '\r') {
len[i1++] = *(l++);
}
} else {
LOGE("Can't find length:%s", buf);
return 0;
}
return atoi(len);
}
void ReqHead(char* outReqBuf, const char *url, char* host)
{
LOGD("http HEAD requst\r\n");
sprintf(outReqBuf, "HEAD %s HTTP/1.1\r\n"
"Accept:*/*\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
"Host: %s\r\n"
"Connection:Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"\r\n\r\n", url, host);
DEBUGHTTP(outReqBuf);
}
void ReqGetM3u8(char* outReqBuf, const char *url, char* host)
{
LOGD("http GET requst:");
if ((NULL == url) || (NULL == host)) {
LOGE("NULL = url or NULL = host");
return;
}
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
"Accept:*/*\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
"Host: %s\r\n"
"Connection: Close\r\n" // Keep-Alive
"Cache-Control: no-cache\r\n"
"\r\n\r\n", url, host);
DEBUGHTTP(outReqBuf);
}
void ReqDataPre(char* outReqBuf, const char *url, char* host, uint32_t startLen, uint32_t endLen)
{
if (0 != endLen) {
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
"Accept:*/*\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
"Host: %s\r\n"
"Proxy-Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n"
"Range: bytes=%d-%d\r\n\r\n", url, host, startLen, endLen - 1);
} else {
sprintf(outReqBuf, "GET %s HTTP/1.1\r\n"
"Accept:*/*\r\n"
"User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.80 Safari/537.36\r\n"
"Host: %s\r\n"
"Proxy-Connection: Keep-Alive\r\n"
"Cache-Control: no-cache\r\n\r\n", url, host);
}
LOGD("http GET requst-%d:", strlen(outReqBuf));
//DEBUGHTTP(outReqBuf);
}
int getIpForHost(const char *host, struct sockaddr_in *ip)
{
struct hostent *he;
struct in_addr **addr_list;
char str[200] ;
he = gethostbyname(host);
if (he == NULL) return 0;
addr_list = (struct in_addr **)he->h_addr_list;
if (addr_list[0] == NULL) return 0;
ip->sin_family = AF_INET;
memcpy(&ip->sin_addr, addr_list[0], sizeof(ip->sin_addr));
return 1;
}
int splitHostUrl(const char* url, char* host, uint16_t *port, char **path)
{
if ((NULL == url) || (NULL == host)) {
LOGE("ERR:url=NULL or Host=NULL\n");
return -1;
}
char* temp1;
char* source = (char*)url;
char portBuf[10] = {0};
while (url) {
source = strstr(source, "//");
if (url == NULL) {
LOGE("ERR:strchr=NULL\n");
return -1;
}
source += 2;
temp1 = strchr(source, ':');
if (temp1 != NULL) {
// try to find '/'
strncpy(host, source, temp1 - source);
temp1 += 1;
source = strchr(source, '/');
if (source == NULL) {
LOGE("ERR:strchr=NULL\n");
return 0;
}
strncpy(portBuf, temp1, source - temp1);
*port = strtoul(portBuf, 0, 10);
*path = source;
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
} else {
// try to find port
temp1 = strchr(source, '/');
if (temp1 == NULL) {
LOGE("ERR:strchr=NULL\n");
return -1;
}
strncpy(host, source, temp1 - source);
*port = 80;
*path = temp1;
LOGD("\nUsed Host[%s] Port[%d],Path:%s\n", host, *port, *path);
}
return 0;
}
return -1;
}
int connectToServer(const char* actUrl, const char* hostName, uint16_t port, int timeOut)
{
struct sockaddr_in remote_ip;
int sock = -1;
int nNetTimeout = timeOut; // socket timeout 1 Sec
int retryCnt = 3;
while (retryCnt--) {
bzero(&remote_ip, sizeof(struct sockaddr_in));
if (1 != inet_aton(hostName, &remote_ip.sin_addr)) {
if (!getIpForHost(hostName, &remote_ip)) {
vTaskDelay(1000 / portTICK_RATE_MS);
LOGE("getIpForHost failed");
continue;
}
}
remote_ip.sin_family = AF_INET;
int sock = socket(PF_INET, SOCK_STREAM, 0);
if (sock == -1) {
LOGE("socket failed errno=%d", errno);
continue;
}
// setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
struct timeval tv_out;
tv_out.tv_sec = 20; //Wait 20 seconds.
tv_out.tv_usec = 0;
setsockopt(sock,SOL_SOCKET,SO_RCVTIMEO,&tv_out, sizeof(tv_out));
remote_ip.sin_port = htons(port);
LOGD("[sock=%d],connecting to server IP:%s,Port:%d...",
sock, ipaddr_ntoa((const ip_addr_t*)&remote_ip.sin_addr.s_addr), port);
if (connect(sock, (struct sockaddr *)(&remote_ip), sizeof(struct sockaddr)) != 0) {
close(sock);
LOGE("Conn err.\n");
vTaskDelay(1000 / portTICK_RATE_MS);
continue;
}
return sock;
}
LOGE("Lost host,connect and getIpForHost timeout");
return -2;
}
void resetDownloadAttr(char *src, uint32_t *type)
{
localHttp.status = 0;
if (localHttp.blockQuit < 0) {
localHttp.blockQuit = 0;
}
localHttp.receivedSize = 0;
localHttp.remaindSize = 0;
localHttp.downloadedSize = 0;
localHttp.uri.srcType = *type;
localHttp.contentTotalSize = 0;
memset(localHttp.uri.str, 0, ESP_URI_LEN);
strncpy(localHttp.uri.str, src, strlen(src));
}
void OnFileDataCB(HttpObj *obj)
{
int ret;
do {
ret = audioBufWrite(obj->reqBuf, obj->receivedSize, 100);
if (ret) {
obj->remaindSize -= obj->receivedSize;
obj->downloadedSize += obj->receivedSize;
// uint32_t rd, wr;
// audioBufPosGet(&rd, &wr);
// LOGD("rd:%x,wr:%x,downloaded=%d, remaind=%d, total=%d, recvSize=%d",
// rd,wr,obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, obj->receivedSize);
break;
} else {
LOGE("audioBufWrite failed ret=%d. rcev=%d,remaind=%d, d=%d", ret,
obj->receivedSize, obj->remaindSize, obj->downloadedSize);
break;
}
} while (0 == obj->blockQuit);
}
void OnM3u8DataCB(HttpObj *obj)
{
obj->remaindSize -= obj->receivedSize;
obj->downloadedSize += obj->receivedSize;
// LOGD(":\n%s", obj->reqBuf);
}
char *GetValidUrl(M3u8Info *pActM3u8, M3u8Seq *actSeq)
{
char *retUrl = NULL;
if ((NULL == actSeq)
|| (NULL == pActM3u8)) {
LOGE("pActM3u8 or actSeq is NULL");
return retUrl;
}
int validM3u8 = -1;
for (uint8_t i = 0; i < 3; i++) {
// LOGD("M3u8 AAC URL,%dth,%s\n", i, pActM3u8->segList[i].url);
if ((actSeq->sub == DEFAULT_AAC_SEQ)
|| (1 == m3u8CheckValid(&pActM3u8->segList[i].seq, (const M3u8Seq*)actSeq))) {
validM3u8 = 1;
retUrl = pActM3u8->segList[i].url;
memcpy(actSeq, &pActM3u8->segList[i].seq, sizeof(pActM3u8->segList[i].seq));
pActM3u8->segList[i].seq.sub = 0;
LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, actSeq->sub, retUrl);
if ((0 == actSeq->sub)
|| (retUrl[0] == '\0')) {
retUrl = NULL;
}
return retUrl;
} else {
// LOGD("Get one valid AAC URL,%dth,seq=%x,%s\n", i, pActM3u8->segList[i].seq.sub, pActM3u8->segList[i].url);
pActM3u8->segList[i].seq.sub = 0;
}
}
if (validM3u8 != 1) {
LOGD("Can not found valid aac url, curtAacSeq=%x", actSeq->sub);
}
return retUrl;
}
int httpDownloading(HttpObj *obj, Callback_Recv recvCB)
{
if ((NULL == obj)
|| (NULL == obj->uri.str)
|| (NULL == obj->reqBuf)
|| (NULL == obj->recvBuf)
|| (0 == strlen(obj->uri.str))) {
LOGE("Pointer is NULL,obj:%x,URL:%x reqbuf:%x recvBuf:%x,len:%d,blockQuit:%d",
obj, obj->uri.str, obj->reqBuf, obj->recvBuf, strlen(obj->uri.str), obj->blockQuit);
return -1;
}
char hostName[32] = { 0 };
int actSocket = -1;
uint32_t contrlDat = 0;
uint8_t modifyProFlag = 0;
int cnt = 0;
int n = 0;
LOGD("\n>>>>>Downloading start:%s,0x%x,remaind=%d,downloaded=%d,total=%d,fill=%d",
obj->uri.str, obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize, audioBufFillGet());
obj->status = 1;
uint16_t ipPort = 80;
char *uriPath = NULL;
do {
// Here will check exit event;
Retry: LOGD("retry new url size=%d", obj->remaindSize);
memset(hostName, 0, sizeof(hostName));
if (0 != splitHostUrl(obj->uri.str, hostName, &ipPort, &uriPath)) {
LOGE("splitHostUrl failed:%s", obj->uri.str);
continue;
}
LOGD("Hostname:%s", hostName);
if ((actSocket = connectToServer((const char*)obj->uri.str, hostName, ipPort, 10000)) >= 0) {
char * datPos = NULL;
bzero(obj->reqBuf, REQUEST_BUF_LEN);
ReqDataPre(obj->reqBuf, uriPath, hostName, obj->downloadedSize, obj->contentTotalSize);
LOGD("Hostname:%s++++++++", hostName);
write(actSocket, obj->reqBuf, strlen(obj->reqBuf));
LOGD("Hostname:%s--------", hostName);
bzero(obj->recvBuf, RECV_BUF_LEN);
datPos = NULL;
cnt = 0;
do {
bzero(obj->reqBuf, REQUEST_BUF_LEN);
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
if ((n > 0) && (cnt <= RECV_BUF_LEN)) {
// DEBUGHTTP("Head is: %s", obj->reqBuf);
memcpy(obj->recvBuf + cnt, obj->reqBuf, n);
datPos = strstr(obj->recvBuf, "\r\n""""\r\n");
if (datPos) {
//DEBUGHTTP("Find CRLF CRLF ok");
// LOGD("Head is: %s", obj->recvBuf);
} else {
LOGE("Find CRLF CRLF failed,wait more data");
}
}
cnt += n;
} while ((datPos == NULL) && (n > 0) && (cnt < RECV_BUF_LEN));
if (n < 0) {
close(actSocket);
continue;
}
if (NULL == datPos) {
// datPos == strstr(obj->recvBuf, "\r\n""""\r\n");
LOGD("Head is: %s", obj->recvBuf);
if (NULL == datPos) {
close(actSocket);
LOGE("Can't Find CRLF CRLF,it's bad response,try again");
continue;
}
}
int ret = checkIsReqOk(obj->recvBuf);
if (ret < 0) {
close(actSocket);
LOGE("Recv a bad resp:%s", obj->recvBuf);
continue;
} else if (ret == 1) {
close(actSocket);
LOGW("Recv a 3xx resp:%s", obj->recvBuf);
memset(obj->uri.str, 0, ESP_URI_LEN);
if (getLocation((const char*)obj->recvBuf, obj->uri.str) < 0) {
LOGE("Find 3xx URL error");
} else {
LOGW("Recv a 3xx resp:%s", obj->uri.str);
}
goto Retry;
}
if (0 == obj->contentTotalSize) obj->contentTotalSize = getFileLength(obj->recvBuf);
datPos += 4;
cnt = cnt - (datPos - obj->recvBuf);
if (0 == obj->remaindSize) {
obj->remaindSize = obj->contentTotalSize;
}
// Save the tail data
bzero(obj->reqBuf, REQUEST_BUF_LEN);
memcpy(obj->reqBuf, datPos, cnt);
LOGD("downloaded=%d, remaind=%d, total=%d, cnt=%d",
obj->downloadedSize, obj->remaindSize, obj->contentTotalSize, cnt);
int writeComplete = 0;
do {
if (writeComplete) {
bzero(obj->reqBuf, REQUEST_BUF_LEN);
n = read(actSocket, obj->reqBuf, REQUEST_BUF_LEN);
cnt = n;
// DEBUGHTTP("recv,cnt:%d\n", cnt);
}
if (n > 0) {
if (cnt > 0) {
obj->receivedSize = cnt;
recvCB(obj);
}
cnt = 0;
writeComplete = 1;
}
} while ((n > 0) && (obj->remaindSize > 0) && (0 == obj->blockQuit));
close(actSocket);
LOGD("Sock[%d] has closed,n=%d,blockQuit=%d", actSocket, n, obj->blockQuit);
} else {
LOGE("Connect is error.");
}
LOGD("Connect closed,file size remaind=%d", obj->remaindSize);
} while ((obj->remaindSize != 0) && (0 == obj->blockQuit));
if (0 == obj->remaindSize) {
obj->status = 2;
} else {
obj->status = 3;
}
LOGD("\n<<<<<Downloading finish:%s,remaind=%d,downloaded=%d,total=%d fill=%d status=%d\n",
obj->uri.str, obj->remaindSize, obj->downloadedSize, obj->contentTotalSize,
audioBufFillGet(), obj->status);
return 0;
}
void fileDownloadTask(void *pvParameters)
{
int n, cnt;
DownloadInstance *downloadObj = (DownloadInstance *)pvParameters;
LOGI("%s is running.%x %x", __func__, pvParameters, downloadObj->threadQuit);
/////////////////////////////
M3u8Seq runningAacSeq = {0, 0, DEFAULT_AAC_SEQ};
M3u8Info *pUsingM3u8 = NULL;
uint32_t mediaSeq = DEFAULT_AAC_SEQ;
downloadObj->threadQuit = 0;
while (downloadObj->threadQuit == 0) {
switch (downloadObj->state) {
case TaskState_Ready:
if ((NULL == actLiveUrl.str)
|| (actLiveUrl.str[0] == '\0')
|| (NULL == localHttp.uri.str )) {
downloadObj->state = TaskState_Idle;
vTaskDelay(200 / portTICK_RATE_MS);
LOGI("Downloading URL is NULL,downloading task paused");
break;
} else {
LOGI("Download task is ready.%s type:%d", actLiveUrl.str, actLiveUrl.type);
}
if (InputSrcType_NetSpec == actLiveUrl.type) {
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
downloadObj->state = TaskState_Running;
audioBufWrRest();
} else if (InputSrcType_NetLiving == actLiveUrl.type) {
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
audioBufWrRest();
mediaSeq = DEFAULT_AAC_SEQ;
downloadObj->state = TaskState_Running;
runningAacSeq.sub = DEFAULT_AAC_SEQ;
if (pUsingM3u8) {
free(pUsingM3u8);
pUsingM3u8 = NULL;
}
pUsingM3u8 = calloc(1, sizeof(M3u8Info));
if (pUsingM3u8 == NULL) {
LOGE("recvBuf malloc error");
break;
}
} else {
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
downloadObj->state = TaskState_Idle;
vTaskDelay(200 / portTICK_RATE_MS);
}
break;
case TaskState_Pause:
LOGI("TaskState_Pause,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
localHttp.downloadedSize,
localHttp.remaindSize);
downloadObj->state = TaskState_Idle;
break;
case TaskState_Resume:
downloadObj->state = TaskState_Running;
LOGI("TaskState_Resume,Total=%d, downloaded=%d,remaind=%d", localHttp.contentTotalSize,
localHttp.downloadedSize,
localHttp.remaindSize);
break;
case TaskState_Running:
if (InputSrcType_NetSpec == localHttp.uri.srcType) {
LOGI("Excute URL:%s", localHttp.uri.str);
httpDownloading(&localHttp, OnFileDataCB);
if (2 == localHttp.status) {
downloadObj->state = TaskState_Idle;
LOGI("Excute URL over, task will be idle.remind[%d]", localHttp.remaindSize);
}
} else if (InputSrcType_NetLiving == localHttp.uri.srcType) {
resetDownloadAttr(actLiveUrl.str, &actLiveUrl.type);
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
LOGD("Excute URL:%s, actLiveUrl.str=%x", localHttp.uri.str, actLiveUrl.str);
httpDownloading(&localHttp, OnM3u8DataCB);
M3u8Info *pActM3u8 = m3u8Parser(localHttp.reqBuf, pUsingM3u8);
if (NULL == pActM3u8) {
LOGE("Parser m3u8 is error");
vTaskDelay(1000 / portTICK_RATE_MS);
break;
}
if ((pActM3u8->mediaSeq <= mediaSeq) && (mediaSeq != DEFAULT_AAC_SEQ)) {
LOGD("mediaSeq has not update,used=%d,new=%d", mediaSeq, pActM3u8->mediaSeq);
vTaskDelay(1000 / portTICK_RATE_MS);
break;
}
char *validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n",
runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
if (NULL == validUrl) {
vTaskDelay(100 / portTICK_RATE_MS);
LOGE("uri.str is NULL,state=%d", downloadObj->state);
break;
}
DecoderObj decoder;
mediaDecoderTaskInfoGet(&decoder);
decoder.musicType = checkMediaType(validUrl);
if (decoder.musicType >= EspAudioMeidaType_M3u) {
LOGE("%s,Music type[%d] is error", validUrl, decoder.musicType);
vTaskDelay(100 / portTICK_RATE_MS);
break;
} else {
mediaDecoderTaskInfoSet(&decoder);
}
do {
resetDownloadAttr(validUrl, &actLiveUrl.type);
memset(localHttp.recvBuf, 0, RECV_BUF_LEN);
memset(localHttp.reqBuf, 0, REQUEST_BUF_LEN);
httpDownloading(&localHttp, OnFileDataCB);
validUrl = GetValidUrl(pActM3u8, &runningAacSeq);
LOGD("AAC URL,runningAacSeq:%x,%x,%x\n", runningAacSeq.sub, runningAacSeq.main, runningAacSeq.date);
if (NULL == validUrl) {
LOGD("uri.str is NULL,state=%d", downloadObj->state);
break;
}
} while (validUrl != NULL);
mediaSeq = pActM3u8->mediaSeq;
} else {
LOGE("Http uri.srcType is not supported[%d]", localHttp.uri.srcType);
downloadObj->state = TaskState_Idle;
vTaskDelay(200 / portTICK_RATE_MS);
}
break;
case TaskState_Stoped:
downloadObj->state = TaskState_Idle;
break;
case TaskState_Idle:
default:
vTaskDelay(250 / portTICK_RATE_MS);
// LOGD("blockQuit[%d] state[%d]", localHttp.blockQuit, downloadObj->state);
break;
}
}
downloadObj->threadQuit = -1;
downloadObj->thread = NULL;
downloadObj->state = TaskState_Stoped;
if (pUsingM3u8) {
free(pUsingM3u8);
pUsingM3u8 = NULL;
}
LOGD("%s is ended...", __func__);
vTaskDelete(NULL);
}
TaskState downloadTaskStateGet()
{
return dlInstance.state;
}
int downloadTaskHTTPStateGet()
{
return localHttp.status;
}
void downloadTaskDownloadSizeSet(int *size)
{
if (NULL == size) {
LOGE("Invalid para");
return ;
}
// localHttp.blockQuit = 1;
localHttp.downloadedSize = *size;
downloadTaskResume();
}
void downloadTaskContentSizeGet(uint32_t *size)
{
if (NULL == size) {
LOGE("Invalid para");
return ;
}
*size = localHttp.contentTotalSize;
}
void downloadTaskInfoSet(UriSrcAttr *uri)
{
if (NULL == uri) {
LOGE("Invalid para");
return ;
}
actLiveUrl.type = uri->srcType;
memset(actLiveUrl.str, 0 , ESP_URI_LEN);
strncpy(actLiveUrl.str, uri->str, strlen(uri->str));
localHttp.blockQuit = 0;
LOGD("Set url ok:%s", actLiveUrl.str);
}
void downloadTaskPause()
{
if (0 == dlInstance.thread) {
dlInstance.state = TaskState_Unknown;
LOGE("dlInstance.thread is NULL");
return;
}
if (TaskState_Running == dlInstance.state) {
localHttp.blockQuit = -1;
}
dlInstance.state = TaskState_Pause;
LOGD("download task state=%d", dlInstance.state);
}
void downloadTaskResume()
{
if (0 == dlInstance.thread) {
dlInstance.state = TaskState_Unknown;
LOGE("dlInstance.thread is NULL");
return;
}
if (TaskState_Pause == dlInstance.state) {
localHttp.blockQuit = 0;
}
dlInstance.state = TaskState_Resume;
LOGD("download task state=%d", dlInstance.state);
}
void downloadTaskCreate(int taskType)
{
if (localHttp.reqBuf) {
free(localHttp.reqBuf);
}
if (localHttp.recvBuf) {
free(localHttp.recvBuf);
}
if (localHttp.uri.str) {
free(localHttp.uri.str);
}
localHttp.reqBuf = calloc(1, REQUEST_BUF_LEN);
if (NULL == localHttp.reqBuf) {
LOGE("reqBuf malloc error");
return;
}
localHttp.recvBuf = calloc(1, RECV_BUF_LEN);
if (NULL == localHttp.recvBuf) {
LOGE("recvBuf malloc error");
free(localHttp.reqBuf);
return;
}
localHttp.uri.str = calloc(1, ESP_URI_LEN);
if (NULL == localHttp.uri.str) {
LOGE("uri.str malloc error");
free(localHttp.reqBuf);
free(localHttp.recvBuf);
return;
}
// mutex_init(&downloadMutex);
// configASSERT(downloadMutex);
xTaskCreate(fileDownloadTask, "fileDownloadTask", (6 * 1024), &dlInstance, PRIO_DOWNLOAD, &dlInstance.thread);
configASSERT(dlInstance.thread);
LOGD("download task state=%d", dlInstance.state);
}
int downloadTaskStart()
{
if (0 == dlInstance.thread) {
dlInstance.state = TaskState_Unknown;
LOGE("dlInstance.thread is NULL");
return -1;
}
if ((actLiveUrl.str == NULL)
|| (actLiveUrl.str[0] == '\0')) {
dlInstance.state = TaskState_Idle;
LOGE("uri.str task is NULL");
return -1;
}
dlInstance.state = TaskState_Ready;
LOGD("download task state=%d, %s, %d", dlInstance.state, actLiveUrl.str, localHttp.blockQuit);
audioBufWrRest();
return 0;
}
void downloadTaskStop(void *que)
{
if (0 == dlInstance.thread) {
dlInstance.state = TaskState_Unknown;
LOGE("dlInstance.thread is NULL");
return;
}
if (dlInstance.state == TaskState_Unknown) {
LOGW("dlInstance.state is TaskState_Unknown");
return;
}
localHttp.blockQuit = 1;
dlInstance.state = TaskState_Stoped;
configASSERT(que);
xQueueSend(que, &localHttp.blockQuit, 0);
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
while ((TaskState_Finished != dlInstance.state)
&& (TaskState_Idle != dlInstance.state)) {
if ((TaskState_Idle == dlInstance.state)) {
localHttp.blockQuit = 0;
break;
}
vTaskDelay(10 / portTICK_RATE_MS);
}
audioBufWrRest();
xQueueReset(que);
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
}
void downloadTaskDestroy()
{
if (0 == dlInstance.thread) {
dlInstance.state = TaskState_Unknown;
LOGE("dlInstance.thread is NULL");
return;
}
LOGD("download task +++++ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
if (0 == dlInstance.threadQuit) {
localHttp.blockQuit = 1;
dlInstance.threadQuit = 1;
dlInstance.state = TaskState_Stoped;
while (1) {
if ((dlInstance.threadQuit == -1)) {
localHttp.blockQuit = 0;
break;
}
vTaskDelay(200 / portTICK_RATE_MS);
}
}
if (localHttp.reqBuf) free(localHttp.reqBuf);
if (localHttp.recvBuf) free(localHttp.recvBuf);
if (localHttp.uri.str) free(localHttp.uri.str);
memset(&localHttp, 0, sizeof(localHttp));
localHttp.reqBuf = NULL;
localHttp.recvBuf = NULL;
localHttp.uri.str = NULL;
dlInstance.state = TaskState_Unknown;
dlInstance.thread = NULL;
// mutex_destroy(&downloadMutex);
// downloadMutex = NULL;
LOGD("download task ------ blockQuit=%d, state=%d", localHttp.blockQuit, dlInstance.state);
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,318 @@
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "inc/M3u8.h"
static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size);
static int m3u8_info_eof();
static int parseSegFromUrl(M3u8Segment* tsp);
static char * strdupmy(const char *s);
unsigned int length;
unsigned int offset;
//////////////////////////////////////////////////////////////////////////////////////
char* trim_str(char *str)
{
char* tmp = str;
while (*str++ != '\r') {
if (*str == '\0' || *str == '\n') {
break;
}
}
*str = '\0';
return tmp;
}
// Must to be free memory
static char * strdupmy(const char *s)
{
size_t len = strlen(s) + 1;
void *new = malloc(len);
if (new == NULL)
return NULL;
return (char *)memcpy(new, s, len);
}
char* split_url(char* url, char* seg_path, char* seg_name)
{
char* temp1;
char rateStr[10] = {0};
int len = strlen(url);
while (url) {
temp1 = strrchr(url, '/');
if (temp1 == NULL) {
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
return NULL;
}
temp1 += 1;
strncpy(seg_path, url, temp1 - url);
strncpy(seg_name, temp1, len - (temp1 - url));
return seg_path;
}
return NULL;
}
int is_blank(char *str)
{
if (0 == strlen(str))
return 1;
else
return 0;
}
static int read_line_from_m3u8_info(char *m3u8_info, char *line_buffer, int buffer_size)
{
int start;
int end = -1;
char cur_char = '\0';
int copy_size;
start = offset;
while (offset < length) {
cur_char = m3u8_info[offset];
if (cur_char == '\r' || cur_char == '\n') {
end = offset;
offset++;
break;
}
offset++;
}
if (end == -1) {
end = length;
}
if (cur_char == '\r') {
offset++;
}
memset(line_buffer, 0, buffer_size);
copy_size = end - start;
if (copy_size > buffer_size - 1) {
copy_size = buffer_size - 1;
}
strncpy(line_buffer, m3u8_info + start, copy_size);
return 1;
}
static int m3u8_info_eof()
{
if (offset >= length) {
return 1;
} else {
return 0;
}
}
int parseSegFromUrl(M3u8Segment* tsp)
{
int len = strlen(tsp->url);
int ret = -1;
char *segment_path = (char*)malloc(len);
char *segment_name = (char*)malloc(len);
if ((segment_path == NULL) | (segment_name == NULL)) {
goto SAVEEXIT;
}
memset(segment_path, 0, len);
memset(segment_name, 0, len);
split_url(tsp->url, segment_path, segment_name);
//http://live.xmcdn.com/192.168.3.134/live/12/24/160411_000003_15f9.ts
//http://live.xmcdn.com/192.168.3.134/live/75/24/160413_082919_12b0.aac
char* temp1 = strchr(segment_name, '.');
char* temp2 = strrchr(segment_name, '_');
if ((temp1 == NULL) | (temp2 == NULL)) {
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
goto SAVEEXIT;
}
*temp1 = '\0';
temp1++;
if (strncmp(temp1, "aac", 3) == 0) {
tsp->fmt = AUDIOFMT_AAC;
} else if (strncmp(temp1, "ts", 3) == 0) {
tsp->fmt = AUDIOFMT_TS;
} else {
tsp->fmt = AUDIOFMT_UNKNOWN;
}
///subSeq
temp2++;
tsp->seq.sub = strtoul(temp2, 0, 16);
////mainSeq
temp2--;
*temp2 = '\0';
temp1 = strrchr(segment_name, '_');
if (temp1 == NULL) {
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
goto SAVEEXIT;
}
temp1++;
tsp->seq.main = strtoul(temp1, 0, 16);
///
temp2 = strchr(segment_name, '_');
if (temp2 == NULL) {
printf("ERR:strchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
goto SAVEEXIT;
}
*temp2 = '\0';
tsp->seq.date = strtoul(segment_name, 0, 16);
temp1 = strrchr(segment_path, '/');
if (temp1 == NULL) {
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
goto SAVEEXIT;
}
*temp1 = '\0';
temp1 = strrchr(segment_path, '/');
if (temp1 == NULL) {
printf("ERR:strrchr=NULL,%s,%d\n", __FUNCTION__, __LINE__);
goto SAVEEXIT;
}
temp1++;
tsp->rate = atoi(temp1);
ret = 0;
SAVEEXIT:
if (segment_path) {
free(segment_path);
}
if (segment_name) {
free(segment_name);
}
return ret;
}
#define ONE_LINE_SIZE 1024
M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8)
{
int has_segment = 0;
if (NULL == m3u8) {
printf("malloc for M3u8Info failed.");
return NULL;
}
char *line = malloc(ONE_LINE_SIZE);
if (NULL == line) {
printf("zalloc for line failed.");
return NULL;
}
memset(line, 0, ONE_LINE_SIZE);
memset(m3u8, 0, sizeof(M3u8Info));
length = strlen(m3u8Str);
offset = 0;
while (!m3u8_info_eof()) {
int result = 0;
char *str = NULL;
if (m3u8->segCount >= MAX_SEGMENT_COUNT) {
printf("segCount >= MAX_SEGMENT_COUNT[%d].", MAX_SEGMENT_COUNT);
break;
}
result = read_line_from_m3u8_info(m3u8Str, line, ONE_LINE_SIZE);
if (!result) {
printf("ERR:read line error from m3u8 info.");
if (line) free(line);
return NULL;
}
if (is_blank(line)) {
continue;
}
str = trim_str(line);
if (has_segment) {
int size = strlen(str) + 1;
m3u8->segList[m3u8->segCount].seq.sub = m3u8->mediaSeq + m3u8->segCount;
// m3u8->segList[m3u8->segCount - 1].url = (char *)malloc(size);
memset(m3u8->segList[m3u8->segCount].url, 0, size);
strcpy(m3u8->segList[m3u8->segCount].url, str);
parseSegFromUrl(&m3u8->segList[m3u8->segCount]);
has_segment = 0;
m3u8->segCount++;
} else {
if (0 == strncmp(str, "#EXTM3U", strlen("#EXTM3U"))) {
} else if (0 == strncmp(str, "#EXT-X-VERSION:", strlen("#EXT-X-VERSION:"))) {
} else if (0 == strncmp(str, "#EXT-X-ALLOW-CACHE:", strlen("#EXT-X-ALLOW-CACHE:"))) {
} else if (0 == strncmp(str, "#EXT-X-TARGETDURATION:", strlen("#EXT-X-TARGETDURATION:"))) {
char *str_duration = str + strlen("#EXT-X-TARGETDURATION:");
m3u8->targetDuration = atoi(trim_str(str_duration));
// printf("Get the TARGETDURATION=%d\n", m3u8->targetDuration);
} else if (0 == strncmp(str, "#EXT-X-MEDIA-SEQUENCE:", strlen("#EXT-X-MEDIA-SEQUENCE:"))) {
char *str_sequence = str + strlen("#EXT-X-MEDIA-SEQUENCE:");
m3u8->mediaSeq = atol(trim_str(str_sequence));
// printf("Get the MEDIA-SEQUENCE=%d\n", m3u8->mediaSeq);
} else if (0 == strncmp(str, "#EXTINF:", strlen("#EXTINF:"))) {
char *str_segment_duration = NULL;
int i = 0;
has_segment = 1;
str_segment_duration = str + strlen("#EXTINF:");
while (str_segment_duration[i] != 0) {
if ((str_segment_duration[i] < '0') || (str_segment_duration[i] > '9')) {
str_segment_duration[i] = 0;
break;
}
i++;
}
m3u8->segList[m3u8->segCount].duration = atoi(str_segment_duration);
} else if (0 == strncmp(str, "#EXT-X-DISCONTINUITY", strlen("#EXT-X-DISCONTINUITY"))) {
} else if (0 == strncmp(str, "#EXT-X-ENDLIST", strlen("#EXT-X-ENDLIST"))) {
} else {
printf("unknown line: %s.", str);
}
}
}
if (line) free(line);
return m3u8;
}
uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre)
{
if (pre->date < new->date) {
return 1;
} else if (pre->date == new->date) {
if (pre->main < new->main) {
return 1;
} else if (pre->main == new->main) {
if ((pre->sub & 0x0000FFFF) < (new->sub & 0x0000FFFF)) {
return 1;
} else {
return 0;
}
} else {
return 0;
}
} else {
return 0;
}
}
void m3u8Destroy(M3u8Info *m3u8)
{
int i = 0;
if (m3u8 == NULL) {
return;
}
free(m3u8);
}
int m3u8_test(char* pStr)
{
//char *m3u8Str = "#EXTM3U\n"
// "#EXT-X-TARGETDURATION:8\n"
// "#EXT-X-MEDIA-SEQUENCE:92595\n"
// "#EXTINF:8,\n"
// "20121120T182851-04-92595.ts\n"
// "#EXTINF:8,\n"
// "20121120T182851-04-92596.ts\n"
// "#EXTINF:8,\n"
// "20121120T182851-04-92597.ts\n"
// "#EXTINF:8,\n"
// "20121120T182851-04-92598.ts\n";
for (int i = 0; i < 10000; i++) {
// M3u8Info *m3u8 = m3u8Parser(pStr, m3u8);
// m3u8Destroy(m3u8);
}
return 1;
}

View file

@ -0,0 +1,370 @@
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "esp_types.h"
#include "stdlib.h"
#include "stdio.h"
#include "audio_log.h"
#include "inc/DecoderCom.h"
#include "EspAudioCom.h"
#include "Storage.h"
#include "Utility.h"
#include "inc/MediaDecoderTask.h"
#define DECODER_TSK_PRIO 8
#define DATA_PKG_SIZE (512*2)
#if 0
#define DEBUGPLY printf
#else
#define DEBUGPLY
#endif
static xQueueHandle rdQue;
void mediaDecoderTask(void *pvParameters);
typedef struct {
TaskState state;
pthread_t thread;
int threadQuit;
TaskState lastState;
DecoderObj player;
} MediaPlayerInstance;
extern uint32_t rdpos;
extern uint32_t wrpos;
MediaPlayerInstance decoderInstance = { 0 };
static StreamInfo streamInfo;
typedef void (*mediaTaskCallback)(uint32_t *state);
static mediaTaskCallback stateCB;
void mediaDecoderTask(void *pvParameters)
{
MediaPlayerInstance *MPI = (MediaPlayerInstance *)pvParameters;
LOGI("%s is running.%x %x", __func__, pvParameters, MPI->threadQuit);
/////////////////////////////
MPI->threadQuit = 0;
int newPos = 0;
uint32_t wrPos, rdPos;
int isLoopNum = 0;
int readSize = DATA_PKG_SIZE;
int writeDataFinished = 0;
while (MPI->threadQuit == 0) {
switch (MPI->state) {
case TaskState_Ready:
if (MPI->player.musicType == EspAudioMeidaType_Unknown) {
vTaskDelay(100);
continue;
}
LOGD("MPI is here,rate=%d,channel=%d,bitLen=%x",
streamInfo.rate,
streamInfo.ch,
streamInfo.bitLen);
MusicInfo setInfo;
setInfo.num_channels = streamInfo.ch;
setInfo.sampling_rate = streamInfo.rate;
mediaHalModeSet(MediaMode_Decode, &setInfo);
mediaHalPlay(MPI->player.musicType);
audioBufPosGet(&rdPos, &wrPos);
if ((InputSrcType_NetSpec == MPI->player.srcType)
|| (InputSrcType_LocalFile == MPI->player.srcType)
|| ((InputSrcType_Stream == MPI->player.srcType) && (MPI->player.totalByteLength != 0))) {
if ((MPI->player.totalByteLength - MPI->player.bytePosition) < DATA_PKG_SIZE) {
readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
} else {
readSize = DATA_PKG_SIZE;
}
} else {
readSize = DATA_PKG_SIZE;
}
LOGD("rdPos=%x,wrPos=%x,readSize=%d, type=%d\r\n", rdPos, wrPos, readSize, MPI->player.srcType);
MPI->state = TaskState_Running;
writeDataFinished = 0;
isLoopNum = 0;
MPI->lastState = TaskState_Ready;
break;
case TaskState_Pause:
mediaHalPause();
LOGI("Pause playing music....");
MPI->state = TaskState_Idle;
MPI->lastState = TaskState_Pause;
break;
case TaskState_Resume:
mediaHalPlay(MPI->player.musicType);
MPI->state = TaskState_Running;
MPI->lastState = TaskState_Resume;
LOGI("Resume playing music....");
break;
case TaskState_Running: {
if (1 == writeDataFinished) {
MusicInfo info;
mediaHalMusicInfoGet(&info);
if (1 == info.bufEmpty) {
MPI->state = TaskState_Stoped;
LOGI("Set state TaskState_Stoped");
} else {
LOGI("Waiting for decoder empty...");
}
vTaskDelay(100 / portTICK_PERIOD_MS);
break;
}
int res = audioBufRead(MPI->player.dat, readSize, 100);
if (res == 0) {
MPI->state = TaskState_Stoped;
LOGD("audio buffer read quit");
break;
}
MediaErr ret = mediaHalDataWrite((uint8_t*)MPI->player.dat, readSize);
if (ret == MediaErr_NoError) {
MPI->player.bytePosition += readSize;
if ((InputSrcType_NetSpec == MPI->player.srcType)
|| (InputSrcType_LocalFile == MPI->player.srcType)
|| ((InputSrcType_Stream == MPI->player.srcType) && (MPI->player.totalByteLength != 0))) {
newPos = MPI->player.bytePosition + DATA_PKG_SIZE;
if (MPI->player.totalByteLength <= newPos) {
writeDataFinished = 1;
readSize = MPI->player.totalByteLength - MPI->player.bytePosition;
MPI->player.bytePosition = MPI->player.totalByteLength;
LOGD("Last byte Pos=%d total=%d", MPI->player.bytePosition, MPI->player.totalByteLength);
break;
} else {
readSize = DATA_PKG_SIZE;
}
}
} else if (MediaErr_CodecError == ret) {
uint32_t rdPOS, wrPOS;
audioBufPosGet(&rdPOS, &wrPOS);
LOGI("ap8048 init failed ret=%x.Try again.rdPOS=%x,wrPOS=%x", ret, rdPOS, wrPOS);
audioBufRdPosSet(&rdPos);
mediaHalStop();
MPI->state = TaskState_Ready;
} else {
LOGE("ap8048 ret error[%x]", ret);
}
MPI->lastState = TaskState_Running;
}
break;
case TaskState_Stoped: {
mediaHalStop();
newPos = 0;
if (MPI->player.bytePosition == MPI->player.totalByteLength) {
MPI->state = TaskState_Finished;
MPI->player.bytePosition = 0;
MPI->player.totalByteLength = 0;
} else {
MPI->state = TaskState_Idle;
}
LOGI("Stop playing music....state[%d]", MPI->state);
MPI->lastState = TaskState_Stoped;
if (stateCB) stateCB(&MPI->state);
break;
}
case TaskState_Finished:
case TaskState_Idle:
default:
vTaskDelay(300 / portTICK_PERIOD_MS);
// LOGD("MPI->state[%d]", MPI->state);
break;
}
}
MPI->threadQuit = -1;
MPI->thread = NULL;
MPI->state = TaskState_Unknown;
MPI->lastState = TaskState_Unknown;
LOGD("%s is ended...", __func__);
vTaskDelete(NULL);
}
void mediaDecoderTaskCb(void *func)
{
stateCB = func;
}
TaskState mediaDecoderTaskStateGet()
{
return decoderInstance.lastState;
}
void mediaDecoderTaskInfoGet(DecoderObj *obj)
{
if (NULL == obj) {
LOGE("Invalid para");
return ;
}
memcpy(obj, &decoderInstance.player, sizeof(*obj));
}
void mediaDecoderStreamInfoSet(StreamInfo *info)
{
if (NULL == info) {
LOGE("Invalid para");
return ;
}
memcpy(&streamInfo, info, sizeof(streamInfo));
decoderInstance.player.totalByteLength = 0;
LOGD("Set Stream info ok,rate=%d,channel=%d,bitLen=%x",
streamInfo.rate,
streamInfo.ch,
streamInfo.bitLen);
}
void mediaDecoderStreamSizeUpdate(uint32_t *size)
{
if (NULL == *size) {
LOGE("Invalid para");
return ;
}
decoderInstance.player.totalByteLength = *size;
LOGD("Stream total size=%d", decoderInstance.player.totalByteLength);
}
void mediaDecoderTaskInfoSet(DecoderObj *obj)
{
if (NULL == obj) {
LOGE("Invalid para");
return ;
}
memcpy(&decoderInstance.player, obj, sizeof(*obj));
LOGD("Set DecoderObj ok,total=%d,type=%d,dat=%x music=%d",
decoderInstance.player.totalByteLength,
decoderInstance.player.srcType,
decoderInstance.player.dat,
decoderInstance.player.musicType);
}
void mediaDecoderTaskPause()
{
if (0 == decoderInstance.thread) {
decoderInstance.state = TaskState_Unknown;
LOGE("decoderInstance.thread is NULL");
return;
}
if (TaskState_Running == decoderInstance.state) {
decoderInstance.state = TaskState_Pause;
}
LOGD("Task state=%d", decoderInstance.state);
}
void mediaDecoderTaskResume()
{
if (0 == decoderInstance.thread) {
decoderInstance.state = TaskState_Unknown;
LOGE("decoderInstance.thread is NULL");
return;
}
decoderInstance.state = TaskState_Resume;
LOGD("Task state=%d", decoderInstance.state);
}
void mediaDecoderTaskCreate()
{
if (NULL != decoderInstance.player.dat) {
free(decoderInstance.player.dat);
}
memset(&decoderInstance, 0, sizeof(decoderInstance));
memset(&streamInfo, 0, sizeof(streamInfo));
decoderInstance.player.dat = calloc(1, DATA_PKG_SIZE);
if (NULL == decoderInstance.player.dat) {
LOGE("decoderInstance.player.dat malloc error");
return;
}
xTaskCreate(mediaDecoderTask, "mediaDecoderTask", (5 * 1024), &decoderInstance, DECODER_TSK_PRIO, &decoderInstance.thread);
configASSERT(decoderInstance.thread);
LOGD("Task state=%d,dat:%x", decoderInstance.state, decoderInstance.player.dat);
rdQue = xQueueCreate(2, 1);
configASSERT(rdQue);
audioBufRdQuitCfg(rdQue);
}
int mediaDecoderTaskStart()
{
if (0 == decoderInstance.thread) {
decoderInstance.state = TaskState_Unknown;
LOGE("decoderInstance.thread is NULL");
return -1;
}
if ((decoderInstance.player.srcType == InputSrcType_NetSpec)
|| (decoderInstance.player.srcType == InputSrcType_LocalFile)) {
if (decoderInstance.player.totalByteLength == 0) {
LOGE("Player parameter is not ready");
decoderInstance.state = TaskState_Idle;
return -1;
}
}
decoderInstance.state = TaskState_Ready;
LOGD("Task state=%d", decoderInstance.state);
audioBufRdRest();
return 0;
}
void mediaDecoderTaskStop()
{
if (0 == decoderInstance.thread) {
decoderInstance.state = TaskState_Unknown;
LOGE("decoderInstance.thread is NULL");
return;
}
if ((decoderInstance.lastState == TaskState_Unknown)
|| (decoderInstance.lastState == TaskState_Stoped)) {
LOGW("dlInstance.state is [%d]", decoderInstance.state);
return;
}
decoderInstance.state = TaskState_Stoped;
configASSERT(rdQue);
xQueueSend(rdQue, &decoderInstance.state, 0);
LOGD("Task state=%d", decoderInstance.state);
while ((TaskState_Finished != decoderInstance.state)
&& (TaskState_Idle != decoderInstance.state)) {
if ((TaskState_Idle == decoderInstance.state)) {
break;
}
vTaskDelay(10 / portTICK_RATE_MS);
}
audioBufRdRest();
int flag;
xQueueReceive(rdQue, &flag, 0);
LOGD("Task state=%d", decoderInstance.state);
}
void mediaDecoderTaskDestroy()
{
if (0 == decoderInstance.threadQuit) {
decoderInstance.state = TaskState_Stoped;
decoderInstance.threadQuit = 1;
while (1) {
if ((decoderInstance.threadQuit == -1)) {
break;
}
vTaskDelay(100 / portTICK_RATE_MS);
}
}
if (NULL != decoderInstance.player.dat) {
free(decoderInstance.player.dat);
}
memset(&decoderInstance.player, 0, sizeof(decoderInstance.player));
memset(&streamInfo, 0, sizeof(streamInfo));
decoderInstance.player.dat = NULL;
decoderInstance.state = TaskState_Unknown;
vQueueDelete(rdQue);
rdQue = NULL;
LOGD("Task state=%d", decoderInstance.state);
}

View file

@ -0,0 +1,42 @@
/*****************************************************************************
*
* File Name : wm_http_client.h
*
* Description: Http client header file.
*
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
* All rights reserved.
*
* Author : wanghf
*
* Date : 2014-6-6
*****************************************************************************/
#ifndef __DECODER_COM_H__
#define __DECODER_COM_H__
#include "esp_types.h"
// HTTP Type Definitions
//#define pthread_t sys_thread_t
typedef enum {
TaskState_Unknown = 0,
TaskState_Idle = 1, // running state
TaskState_Running = 2,
TaskState_Stoped = 3,
TaskState_Finished = 4,
TaskState_Ready = 10, //control state
TaskState_Resume = 11,
TaskState_Pause = 12,
} TaskState;
#endif //__DECODER_COM_H__

View file

@ -0,0 +1,46 @@
/*****************************************************************************
*
* File Name : wm_http_client.h
*
* Description: Http client header file.
*
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
* All rights reserved.
*
* Author : wanghf
*
* Date : 2014-6-6
*****************************************************************************/
#ifndef HTTP_CLIENT_H
#define HTTP_CLIENT_H
#include "esp_types.h"
#include "lwip/sys.h"
#include "DecoderCom.h"
#define ESP_URI_LEN 1024
typedef struct {
char *str;
int srcType; // 0:specific net audio; 1:m3u8 files; 2:audio data files
// int setStartBytePos;
} UriSrcAttr;
TaskState downloadTaskStateGet();
void downloadTaskContentSizeGet(uint32_t *size);
void downloadTaskInfoSet(UriSrcAttr *obj);
int downloadTaskHTTPStateGet();
void downloadTaskPause();
void downloadTaskResume();
int downloadTaskStart();
void downloadTaskStop();
void downloadTaskCreate(int taskType);
void downloadTaskDestroy();
#endif //

View file

@ -0,0 +1,79 @@
#ifndef _M3U8_H_
#define _M3U8_H_
#include "esp_types.h"
#define MAX_SEGMENT_COUNT 3
//
typedef enum {
AUDIOFMT_UNKNOWN = 0,
AUDIOFMT_AAC = 1,
AUDIOFMT_TS = 2,
} AUDIOFMT;
typedef struct {
size_t date;
size_t main;
size_t sub;
} M3u8Seq;
//
typedef struct {
int duration;
int rate;
AUDIOFMT fmt;
char url[128];
char name[256];
M3u8Seq seq;
} M3u8Segment;
//
typedef struct _M3u8Info {
int targetDuration;
size_t mediaSeq;
int segCount;
M3u8Segment segList[MAX_SEGMENT_COUNT];
} M3u8Info;
typedef struct _audioUrlObj {
AUDIOFMT fmt;
uint32_t uflag; // 0-empty;1-ready;2-using;3-used;
uint32_t idx; // stream sequence
// uint32_t totalTime; // time of music,live:0
char *url;
char *radioName;
char *musicName;
struct _audioUrlObj *next;
} audioUrlObj;
uint8_t m3u8CheckValid(const M3u8Seq* new, const M3u8Seq* pre);
/**
* [m3u8_parser Parser the m3u8 string]
* @param m3u8_string [To be parser string]
* @return [m3u8 object, NULL->failed]
*/
M3u8Info *m3u8Parser(char *m3u8Str, M3u8Info* m3u8);
/**
* [m3u8_destroy Destroy the m3u8 struct]
* @param m3u8 [m3u8 struct]
*/
void m3u8Destroy(M3u8Info *m3u8);
/**
* [m3u8_save description]
* @param m3u8 [m3u8 struct]
* @param m3u8_path [file path]
* @param ts_segment_url_prefix [prefix will be fill]
* @return [0->failed;1->successed]
*/
//int m3u8_save(M3u8Info *m3u8, char *m3u8_path, char *ts_segment_url_prefix);
int m3u8_test(char* pStr);
#endif

View file

@ -0,0 +1,66 @@
/*****************************************************************************
*
* File Name : wm_http_client.h
*
* Description: Http client header file.
*
* Copyright (c) 2014 Winner Microelectronics Co., Ltd.
* All rights reserved.
*
* Author : wanghf
*
* Date : 2014-6-6
*****************************************************************************/
#ifndef __PLAYERTASK_H__
#define __PLAYERTASK_H__
#include "esp_types.h"
#include "EspAudioCom.h"
#include "EspAudio.h"
#include "lwip/sys.h"
#include "MediaHal.h"
//Type Definitions
typedef struct {
char *dat;
InputSrcType srcType;
EspAudioMeidaType musicType;
uint32_t totalByteLength;
uint32_t bytePosition;
int codecVer;
int codecType; // 0:hardware; 1:software
} DecoderObj;
typedef struct {
uint32_t rate;
uint32_t ch;
uint32_t bitLen;
uint32_t size; // 0xFFFFFFFF stream length is infinite
} StreamInfo;
TaskState mediaDecoderTaskStateGet();
void mediaDecoderStreamInfoSet(StreamInfo *info);
void mediaDecoderTaskInfoGet(DecoderObj *obj);
void mediaDecoderTaskInfoSet(DecoderObj *obj);
void mediaDecoderTaskPause();
void mediaDecoderTaskResume();
int mediaDecoderTaskStart();
void mediaDecoderTaskStop();
void mediaDecoderTaskCreate();
void mediaDecoderTaskDestroy();
void mediaDecoderVolSet();
void mediaDecoderVolGet();
void mediaDecoderMusicInfoGet();
void mediaDecoderDecodeTimeGet();
void mediaDecoderModeSet();
void mediaDecoderStreamSizeUpdate(uint32_t *size);
void mediaDecoderTaskCb(void *func);
#endif //__PLAYERTASK_H__

View file

@ -0,0 +1,300 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "freertos/queue.h"
#include "stdlib.h"
#include "stdio.h"
#include "DecoderCom.h"
#include "EspAudioCom.h"
#include "MediaHal.h"
#include "EspAudioRecorder.h"
#include "Ap80xx.h"
#define RECORD_TSK_PRIO 6
#define RECORDER_PKG_SIZE 1024
typedef enum {
RecorderEventType_Unknown,
RecorderEventType_Start,
RecorderEventType_Stop,
RecorderEventType_Pause,
RecorderEventType_Resume,
RecorderEventType_Quit,
} RecorderEventType;
typedef struct {
RecorderEventType type;
void *value;
} RecorderEventInfo;
static xTaskHandle recorderThread;
static xQueueHandle recorderEventQue;
static RecorderState recTaskState;
static MusicInfo streamInfo;
void MediaEncoderTask(void *pvParameters)
{
LOGI("%s is running.%x %x", __func__);
/////////////////////////////
RecorderEventInfo eventInfo ;
static RecorderAttr s_attr;
static int recordStartFlag = 0;
eventInfo.type = RecorderEventType_Unknown;
eventInfo.value = NULL;
uint8_t *recvData = malloc(RECORDER_PKG_SIZE);
if (NULL == recvData) {
LOGE("malloc failed");
return ;
}
memset(recvData, 0, RECORDER_PKG_SIZE);
while (1) {
if (xQueueReceive(recorderEventQue, &eventInfo, 10)) {
switch (eventInfo.type) {
case RecorderEventType_Start: {
MediaState mediaState;
mediaHalStatusGet(&mediaState);
LOGD("Start recording ...%d", mediaState);
if (MediaState_Initialized > mediaState) {
mediaHalInit();
LOGD("Need to init codec driver...[%d]", mediaState);
}
if (eventInfo.value) {
memcpy(&s_attr, eventInfo.value, sizeof(s_attr));
free(eventInfo.value);
eventInfo.value = NULL;
LOGI("recv:channel=%d, rate=%d, encodeType=%d, func=%p",
s_attr.channel, s_attr.rate, s_attr.encodeType, s_attr.func);
streamInfo.sampling_rate =s_attr.rate;
streamInfo.num_channels = s_attr.channel;
streamInfo.stream_type = s_attr.encodeType;
mediaHalModeSet(MediaMode_Encode, &streamInfo);
recordStartFlag = 1;
recTaskState = RecorderState_Recording;
LOGI("Start recording ....");
} else {
LOGE("eventInfo.value = NULL");
}
break;
}
case RecorderEventType_Pause: {
if (RecorderState_Recording == recTaskState) {
recordStartFlag = 0;
recTaskState = RecorderState_Paused;
LOGI("Pause recording");
}
break;
}
case RecorderEventType_Resume: {
if (RecorderState_Paused == recTaskState) {
recordStartFlag = 1;
recTaskState = RecorderState_Recording;
LOGI("Resume recording");
}
break;
}
case RecorderEventType_Stop: {
recordStartFlag = 0;
recTaskState = RecorderState_Stoped;
apSetDecodeMode();
memset(&streamInfo, 0, sizeof(streamInfo));
LOGI("Stop recording");
break;
}
case RecorderEventType_Quit: {
recordStartFlag = 0;
recTaskState = RecorderState_Unknown;
LOGI("MediaEncoderTask will be quit");
goto encoderTaskQuit;
}
default:
vTaskDelay(250 / portTICK_RATE_MS);
LOGE("Event type does not support[%d]", eventInfo.type);
break;
}
}
// LOGD("stack left %d byte\n", uxTaskGetStackHighWaterMark(NULL));
if (recordStartFlag) {
int len = 0;
int ret = mediaHalDataRead(recvData, &len);
if ((ret != 0) || (len == 1)) {
LOGE("mediaHalDataRead failed,ret=%d len=%d", ret, len);
continue;
} else {
// LOGD("mediaHalDataRead ok,ret=%d len=%d", ret, len);
if (len>0) {
s_attr.func(recvData, (uint32_t*)&len);
}
}
}
}
encoderTaskQuit:
free(recvData);
recvData = NULL;
configASSERT(recorderEventQue);
vQueueDelete(recorderEventQue);
recorderEventQue = NULL;
recorderThread = NULL;
LOGI("%s is ended...", __func__);
vTaskDelete(NULL);
}
EspAudioErr EspAudioRecorderStateGet(RecorderState *state)
{
if (NULL == state) {
LOGE("Invalid para,%p", state);
return EspAudioErr_InvalidPara;
}
*state = recTaskState;
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderInit(void)
{
if (NULL == recorderThread) {
xTaskCreate(MediaEncoderTask, "MediaEncoderTask", (5*1024), NULL, RECORD_TSK_PRIO, &recorderThread);
configASSERT(recorderThread);
}
if (NULL == recorderEventQue) {
recorderEventQue = xQueueCreate(4, sizeof(RecorderEventInfo));
configASSERT(recorderEventQue);
}
LOGD("recorder has been created, %p,%p", recorderThread, recorderEventQue);
recTaskState = RecorderState_Init;
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderStart(RecorderAttr *recorderAttr)
{
if ((NULL == recorderAttr)
|| (NULL == recorderThread)
|| (NULL == recorderEventQue)) {
LOGE("Invalid para, %p,%p,%p", recorderAttr, recorderThread, recorderEventQue);
return EspAudioErr_InvalidPara;
}
if (NULL == recorderAttr->func) {
LOGE("Invalid para, %p", recorderAttr->func);
return EspAudioErr_InvalidPara;
}
RecorderAttr *attr = malloc(sizeof(RecorderAttr));
if (NULL == attr) {
LOGE("Malloc failed");
return EspAudioErr_NoMem;
}
attr->channel = recorderAttr->channel;
attr->rate = recorderAttr->rate;
attr->encodeType = recorderAttr->encodeType;
attr->func = recorderAttr->func;
RecorderEventInfo eventInfo ;
eventInfo.type = RecorderEventType_Start;
eventInfo.value = attr;
LOGD("channel=%d, rate=%d, encodeType=%d, func=%p",
attr->channel, attr->rate, attr->encodeType, attr->func);
configASSERT(recorderEventQue);
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
LOGE("EspAudioRecorderStart, queue send failed");
} else {
LOGD("EspAudioRecorderStart, send sucessed");
}
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderPause(void)
{
if ((NULL == recorderThread)
|| (NULL == recorderEventQue)) {
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
return EspAudioErr_InvalidPara;
}
RecorderEventInfo eventInfo ;
eventInfo.type = RecorderEventType_Pause;
eventInfo.value = NULL;
configASSERT(recorderEventQue);
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
LOGE("RecorderEventType_Pause, queue send failed");
} else {
LOGD("RecorderEventType_Pause, send sucessed");
}
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderResume(void)
{
if ((NULL == recorderThread)
|| (NULL == recorderEventQue)) {
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
return EspAudioErr_InvalidPara;
}
RecorderEventInfo eventInfo ;
eventInfo.type = RecorderEventType_Resume;
eventInfo.value = NULL;
configASSERT(recorderEventQue);
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
LOGE("RecorderEventType_Resume, queue send failed");
} else {
LOGD("RecorderEventType_Resume, send sucessed");
}
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderStop(void)
{
if ((NULL == recorderThread)
|| (NULL == recorderEventQue)) {
LOGE("Invalid para, %p,%p", recorderThread, recorderEventQue);
return EspAudioErr_InvalidPara;
}
RecorderEventInfo eventInfo ;
eventInfo.type = RecorderEventType_Stop;
eventInfo.value = NULL;
configASSERT(recorderEventQue);
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
LOGE("RecorderEventType_Stop, queue send failed");
} else {
LOGD("RecorderEventType_Stop, send sucessed");
}
return EspAudioErr_NoErr;
}
EspAudioErr EspAudioRecorderUninit(void)
{
if ((NULL == recorderThread)
|| (NULL == recorderEventQue)) {
LOGE("recorderThread=%p, recorderEventQue=%p", recorderThread, recorderEventQue);
return EspAudioErr_InvalidPara;
}
RecorderEventInfo eventInfo ;
eventInfo.type = RecorderEventType_Quit;
eventInfo.value = NULL;
configASSERT(recorderEventQue);
if (pdTRUE != xQueueSend(recorderEventQue, &eventInfo, 0)) {
LOGE("RecorderEventType_Quit, queue send failed");
} else {
LOGD("RecorderEventType_Quit, send sucessed");
}
return EspAudioErr_NoErr;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,53 @@
#include <stdint.h>
static const uint16_t gCRC16TableNBS[256] =
{
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
uint16_t GetCRC16NBS(uint8_t* data, uint32_t length)
{
uint16_t crc = 0;
uint8_t temp;
while(length--)
{
temp = (unsigned char)(crc >> 8); // get high byte
crc <<= 8; // get low byte
crc ^= gCRC16TableNBS[*data ^ temp];
data++;
}
return crc;
}

View file

@ -0,0 +1,387 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "dma.h"
#include "rom/ets_sys.h"
#include "string.h"
#include "stdlib.h"
#define QUEUE_BLOCK_LENGTH (4096L)
#define DMA_DBG_WARING_ENABLE (0)
#define DMA_DBG_ERROR_ENABLE (0)
#define DMA_INFO_ENABLE (0)
#define DMA_DBG_ENABLE (0)
//DBG INFOR
#if DMA_DBG_ENABLE
#define DMA_DBG(format,...) do{\
ets_printf("[dbg][%s#%u]",__FUNCTION__,__LINE__);\
ets_printf(format,##__VA_ARGS__);\
}while(0)
#else
#define DMA_DBG(...)
#endif
#if DMA_INFO_ENABLE
#define DMA_INFO(format,...) do{\
ets_printf("[info][%s#%u]",__FUNCTION__,__LINE__);\
ets_printf(format,##__VA_ARGS__);\
}while(0)
#else
#define DMA_INFO(...)
#endif
#if DMA_DBG_WARNING_ENABLE
#define DMA_WARNING(format,...) do{\
ets_printf("[waring][%s#%u]",__FUNCTION__,__LINE__);\
ets_printf(format,##__VA_ARGS__);\
}while(0)
#else
#define DMA_WARNING(...)
#endif
#if DMA_DBG_ERROR_ENABLE
#define DMA_ERROR(format,...) do{\
ets_printf("[error][%s#%u]",__FUNCTION__,__LINE__);\
ets_printf(format,##__VA_ARGS__);\
}while(0)
#else
#define DMA_ERROR(...)
#endif
void dma_show_queue(ping_pong_buf_t *pcfg)
{
uint32_t i;
DMA_INFO("obj=%x \r\n", pcfg);
DMA_INFO("ping bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->ping->backup_queue, pcfg->ping->buffer_addr, pcfg->ping->backup_queue.next_link_ptr);
DMA_INFO("ping first_que=%x, %08x, buf=%x\r\n", pcfg->ping->first_queue,*pcfg->ping->first_queue, pcfg->ping->buffer_addr);
DMA_INFO("ping last_que=%x, %08x, buf=%x\r\n", pcfg->ping->last_queue, *pcfg->ping->last_queue, pcfg->ping->buffer_addr);
DMA_INFO("pong bck que=%x buf=%x,next_link_ptr=%x\r\n", pcfg->pong->backup_queue, pcfg->pong->buffer_addr, pcfg->pong->backup_queue.next_link_ptr);
DMA_INFO("pong first_que=%x, %08x, buf=%x\r\n", pcfg->pong->first_queue, *pcfg->pong->first_queue, pcfg->pong->buffer_addr);
DMA_INFO("pong last_que=%x, %08x, buf=%x\r\n", pcfg->pong->last_queue, *pcfg->pong->last_queue, pcfg->pong->buffer_addr);
dma_queue_t *addr = (dma_queue_t*)pcfg->ping->first_queue;
dma_queue_t *addr1 = (dma_queue_t*)pcfg->pong->first_queue;
for (i = 0; i < pcfg->queue_cnt; ++i) {
DMA_INFO("ping queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
addr->buf_ptr,addr->data_length, addr->block_size, addr, addr->next_link_ptr);
addr = (dma_queue_t*)addr->next_link_ptr;
}
for (i = 0; i < pcfg->queue_cnt; ++i) {
DMA_INFO("pong queue%d buf:%08x,len=%d,size=%d,cur_link:%08x,next_link:%08x\r\n", i,
addr1->buf_ptr,addr1->data_length, addr1->block_size, addr1, addr1->next_link_ptr);
addr1 = (dma_queue_t*)addr1->next_link_ptr;
}
}
/**
* @brief Fill a link
*
*/
static void fill_one_link(uint8_t own, uint8_t eof, uint8_t sub_sof, uint16_t size, uint16_t length,
uint32_t *buf_ptr, dma_queue_t *nxt_ptr, dma_queue_t *i2s_queue)
{
i2s_queue->owner = own;
i2s_queue->eof = eof;
i2s_queue->sub_sof = sub_sof;
i2s_queue->data_length = 0x0FFF & length;
i2s_queue->block_size = size ;
i2s_queue->buf_ptr = (uint32_t)buf_ptr;
i2s_queue->next_link_ptr = (uint32_t)nxt_ptr;
i2s_queue->unused = 0;
}
/**
* @brief Fill the queue
*
*/
static int dma_queue_fill(uint32_t cnt, uint32_t len, ping_pong_buf_t *cfg)
{
if (0 == cnt) {
return -1;
}
// ping queue list
dma_queue_t *pingAry[cnt];
// pong queue list
dma_queue_t *pongAry[cnt];
uint32_t i, j;
memset(&pingAry, 0, sizeof(pingAry));
memset(&pongAry, 0, sizeof(pongAry));
cnt = 1;
for (i = 0; i < cnt; ++i) {
pingAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
if (pingAry[i] == NULL) {
for (j = 0; j < i; ++j) {
free(pingAry[j]);
pingAry[j] = NULL;
}
return -2;
}
}
for (i = 0; i < cnt; ++i) {
pongAry[i] = (dma_queue_t*)malloc(sizeof(dma_queue_t));
if (NULL == pongAry[i]) {
for (j = 0; j < cnt; ++j) {
free(pingAry[j]);
pingAry[j] = NULL;
}
for (j = 0; j < i; ++j) {
free(pongAry[j]);
pongAry[j] = NULL;
}
return -2;
}
}
cfg->ping->first_queue = pingAry[0];
cfg->pong->first_queue = pongAry[0];
if (1 == cnt) {
cfg->ping->last_queue = pingAry[0];
cfg->pong->last_queue = pongAry[0];
} else {
cfg->ping->last_queue = pingAry[cnt - 1];
cfg->pong->last_queue = pongAry[cnt - 1];
}
uint32_t remainSize = len;
uint32_t bufSize = QUEUE_BLOCK_LENGTH;
for (i = 0; i < cnt; ++i) {
if (1 == cnt) {
// Queue list include only one link, and set up eof bit.
if (QUEUE_BLOCK_LENGTH == len) {
bufSize = len - 1;
} else {
bufSize = len;
}
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr, pongAry[i], pingAry[i]);
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr, pingAry[i], pongAry[i]);
} else {
if (i == (cnt - 1)) {
// ping/pong queue list last link connect to the pong/ping first link, and set up eof bit.
bufSize = remainSize;
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
pongAry[0], pingAry[i]);
fill_one_link(1, 1, 0, bufSize, bufSize, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i),
pingAry[0], pongAry[i]);
} else {
// Conncet the next link.
fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->ping->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pingAry[i + 1], pingAry[i]);
fill_one_link(1, 0, 0, bufSize - 1, bufSize - 1, cfg->pong->buffer_addr + ((QUEUE_BLOCK_LENGTH / sizeof(uint32_t)) * i), pongAry[i + 1], pongAry[i]);
}
}
remainSize -= bufSize;
}
return 0;
}
/**
* @brief Create a ping-pong buffer object used by DMA.
*
*/
ping_pong_buf_t* dma_buf_create(uint32_t bufLen)
{
if (0 == bufLen) {
return NULL;
}
uint32_t i, j;
uint32_t queue_cnt ;
uint8_t * pBuf = NULL;
i = bufLen / QUEUE_BLOCK_LENGTH;
j = bufLen % QUEUE_BLOCK_LENGTH;
if (0 == j) {
queue_cnt = i;
} else {
queue_cnt = i + 1;
}
DMA_INFO("\r\nbufLen=%d queue_cnt=%d\r\n", bufLen, queue_cnt);
ping_pong_buf_t* pcfg;
pcfg = (ping_pong_buf_t*)malloc(sizeof(ping_pong_buf_t));
if (NULL == pcfg) {
return NULL;
}
pBuf = ((uint8_t*)malloc(bufLen * 2)); // buflen is number of bytes buffer.malloc ping and pong buffer.
pcfg->ping = (dma_element_t*)malloc(sizeof(dma_element_t));
pcfg->pong = (dma_element_t*)malloc(sizeof(dma_element_t));
if ((NULL == pBuf)
|| (NULL == pcfg->pong)
|| (NULL == pcfg->ping)) {
free(pBuf);
pBuf = NULL;
free(pcfg->pong);
pcfg->pong = NULL;
free(pcfg->ping);
pcfg->ping = NULL;
free(pcfg);
pcfg = NULL;
DMA_INFO("Malloc ping->buffer_addr failed");
return NULL;
}
memset(pBuf, 0, (bufLen * 2));
memset(pcfg->ping, 0, sizeof(dma_element_t));
memset(pcfg->pong, 0, sizeof(dma_element_t));
pcfg->ping->buffer_addr = (uint32_t*)pBuf;
pcfg->pong->buffer_addr = (uint32_t*)(pBuf + bufLen);
pcfg->queue_cnt = queue_cnt; // Number of queue
if (dma_queue_fill(queue_cnt, bufLen, pcfg) < 0) {
free(pcfg->ping->buffer_addr);
pcfg->ping->buffer_addr = NULL;
free(pcfg->pong->buffer_addr);
pcfg->pong->buffer_addr = NULL;
free(pBuf);
pBuf = NULL;
free(pcfg->pong);
pcfg->pong = NULL;
free(pcfg->ping);
pcfg->ping = NULL;
free(pcfg);
pcfg = NULL;
return NULL;
}
pcfg->len = bufLen; // Buffer length
dma_show_queue(pcfg);
return pcfg;
}
static esp_err_t dma_queue_reset(int32_t que_size, dma_element_t *obj)
{
if (NULL == obj) {
return ESP_FAIL;
}
// No need reset;
if (0 == obj->backup_queue.next_link_ptr) {
return ESP_OK;
}
dma_queue_t *dmaQueCur = obj->first_queue;
dma_queue_t *dmaQueNext = NULL;
if (que_size > 1) {
while (dmaQueNext != obj->first_queue) {
dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
if ((dma_queue_t*)obj->backup_queue.next_link_ptr == dmaQueNext) {
DMA_INFO("find next_link_ptr=%x \r\n", dmaQueNext);
break;
}
dmaQueCur = dmaQueNext;
}
}
memcpy(dmaQueCur, &obj->backup_queue, sizeof(obj->backup_queue));
memset(&obj->backup_queue, 0, sizeof(obj->backup_queue));
return ESP_OK;
}
/**
* @brief Reset the dma buffer length.
*
*/
esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj)
{
if (NULL == obj) {
return ESP_FAIL;
}
dma_queue_t *dmaQueCur = obj->ping->first_queue;
dma_queue_t *dmaQueNext = NULL;
esp_err_t ret = ESP_OK;
DMA_INFO("next_link_ptr=%x lenght=%d\r\n", obj->ping->backup_queue.next_link_ptr, obj->ping->first_queue->data_length);
obj->ping->first_queue->owner = 1;
obj->ping->last_queue->owner = 1;
obj->pong->first_queue->owner = 1;
obj->pong->last_queue->owner = 1;
obj->pong->first_queue->data_length = 32;
obj->pong->last_queue->data_length = 32;
obj->ping->first_queue->data_length = 32;
obj->ping->last_queue->data_length = 32;
ret = dma_queue_reset(obj->queue_cnt, obj->ping);
ret += dma_queue_reset(obj->queue_cnt, obj->pong);
//dma_show_queue(obj);
DMA_INFO("[%s # %u lenght=%d]\r\n",__FUNCTION__,__LINE__, obj->ping->first_queue->data_length);
return ret;
}
/**
* @brief Set the buffer length before the start.
*
*/
esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len)
{
if (NULL == obj) {
return ESP_FAIL;
}
if (len < obj->len) {
int i, k, cnt;
i = len / QUEUE_BLOCK_LENGTH;
k = len % QUEUE_BLOCK_LENGTH;
if (0 == k) {
cnt = i;
} else {
cnt = i + 1;
}
dma_queue_t *dmaQueCur = element->first_queue;
dma_queue_t *dmaQueNext = NULL;
while (--cnt) {
dmaQueNext = (dma_queue_t*)dmaQueCur->next_link_ptr;
dmaQueCur = dmaQueNext;
}
memcpy(&element->backup_queue, (dma_queue_t*)dmaQueCur, sizeof(element->backup_queue));
dmaQueCur->next_link_ptr = 0;
dmaQueCur->data_length = k;
}
return ESP_OK;
}
/**
* @brief Destroy the ping-pong buffer instance.
*
*/
void dma_buf_destroy(ping_pong_buf_t *obj)
{
ping_pong_buf_t *temp = obj;
dma_show_queue(temp);
if (NULL != temp) {
// Free the link list
uint32_t i = 0;
dma_queue_t *curtCfg = temp->ping->first_queue;
dma_queue_t *nextCfg = NULL;
for (i = 0; i < temp->queue_cnt; ++i) {
nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
free(curtCfg);
curtCfg = NULL;
curtCfg = nextCfg;
}
curtCfg = temp->pong->first_queue;
nextCfg = NULL;
for (i = 0; i < temp->queue_cnt; ++i) {
nextCfg = (dma_queue_t*)curtCfg->next_link_ptr;
free(curtCfg);
curtCfg = NULL;
curtCfg = nextCfg;
}
// Free the buffer
free(temp->ping->buffer_addr);
temp->ping->buffer_addr = NULL;
free(temp->ping);
temp->ping = NULL;
free(temp->pong);
temp->pong = NULL;
free(temp);
temp = NULL;
}
}

View file

@ -0,0 +1,350 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "rom/ets_sys.h"
#include "driver/gpio.h"
#include "i2c_soft.h"
static uint8_t m_nLastSDA;
static uint8_t m_nLastSCL;
/******************************************************************************
* FunctionName : i2c_master_setDC
* Description : Internal used function -
* set i2c SDA and SCL bit value for half clk cycle
* Parameters : uint8_t SDA
* uint8_t SCL
* Returns : NONE
*******************************************************************************/
static void i2c_master_setDC(uint8_t SDA, uint8_t SCL)
{
SDA &= 0x01;
SCL &= 0x01;
m_nLastSDA = SDA;
m_nLastSCL = SCL;
//ETS_INTR_LOCK();
if ((0 == SDA) && (0 == SCL)) {
I2C_MASTER_SDA_LOW_SCL_LOW();
} else if ((0 == SDA) && (1 == SCL)) {
I2C_MASTER_SDA_LOW_SCL_HIGH();
} else if ((1 == SDA) && (0 == SCL)) {
I2C_MASTER_SDA_HIGH_SCL_LOW();
} else {
I2C_MASTER_SDA_HIGH_SCL_HIGH();
}
//ETS_INTR_UNLOCK();
}
/******************************************************************************
* FunctionName : i2c_master_getDC
* Description : Internal used function -
* get i2c SDA bit value
* Parameters : NONE
* Returns : uint8_t - SDA bit value
*******************************************************************************/
static uint8_t i2c_master_getDC(void)
{
uint8_t sda_out;
//ETS_INTR_LOCK();
//sda_out = GPIO_INPUT_GET(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
sda_out = gpio_get_level(GPIO_ID_PIN(I2C_MASTER_SDA_GPIO));
//ETS_INTR_UNLOCK();
return sda_out;
}
/******************************************************************************
* FunctionName : i2c_master_init
* Description : initilize I2C bus to enable i2c operations
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_init(void)
{
uint8_t i;
i2c_master_setDC(1, 0);
i2c_master_wait(5);
// when SCL = 0, toggle SDA to clear up
i2c_master_setDC(0, 0) ;
i2c_master_wait(5);
i2c_master_setDC(1, 0) ;
i2c_master_wait(5);
// set data_cnt to max value
for (i = 0; i < 28; i++) {
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
}
// reset all
i2c_master_stop();
//return;
}
/******************************************************************************
* FunctionName : i2c_master_gpio_init
* Description : config SDA and SCL gpio to open-drain output mode,
* mux and gpio num defined in i2c_master.h
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_gpio_init(void)
{
gpio_config_t io_config;
io_config.pin_bit_mask= (I2C_MASTER_SDA_PIN) | (I2C_MASTER_SCL_PIN);
io_config.mode= GPIO_MODE_INPUT_OUTPUT_OD;
io_config.pull_up_en= GPIO_PULLUP_ENABLE;
io_config.pull_down_en= GPIO_PULLDOWN_DISABLE;
io_config.intr_type = GPIO_PIN_INTR_DISABLE;
gpio_config(&io_config);
#if 0
io_config.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
io_config.gpio_mode_sel = GPIO_MODE_OUTPUT_OD;
io_config.gpio_pin_sel = I2C_MASTER_SCL_PIN;
io_config.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
io_config.gpio_pullup_sel = GPIO_PULLUP_ENABLE;
gpio_config(&io_config);
#endif
#if 0
ETS_INTR_UNLOCK();
// Set to GPIO function
PIN_FUNC_SELECT(I2C_MASTER_SDA_MUX, I2C_MASTER_SDA_FUNC);
PIN_FUNC_SELECT(I2C_MASTER_SCL_MUX, I2C_MASTER_SCL_FUNC);
// Enable input
SET_PERI_REG_MASK(I2C_MASTER_SDA_MUX, FUN_IE);
GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO),
GPIO_REG_READ(GPIO_PIN_ADDR(I2C_MASTER_SDA_GPIO)) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SDA_GPIO));
GPIO_REG_WRITE(GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO),
GPIO_PIN_ADDR(I2C_MASTER_SCL_GPIO) | GPIO_PIN_PAD_DRIVER_SET(GPIO_PAD_DRIVER_ENABLE)); //open drain;
GPIO_REG_WRITE(GPIO_ENABLE, GPIO_REG_READ(GPIO_ENABLE) | (1 << I2C_MASTER_SCL_GPIO));
I2C_MASTER_SDA_HIGH_SCL_HIGH();
PIN_PULLUP_EN(I2C_MASTER_SDA_MUX);
PIN_PULLUP_EN(I2C_MASTER_SCL_MUX);
ETS_INTR_UNLOCK();
#endif
i2c_master_init();
}
/******************************************************************************
* FunctionName : i2c_master_start
* Description : set i2c to send state
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_start(void)
{
// ETS_INTR_UNLOCK();
i2c_master_setDC(1, m_nLastSCL);
i2c_master_wait(5);
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
i2c_master_setDC(0, 1);
i2c_master_wait(5); // sda 0, scl 1
// ETS_INTR_UNLOCK();
}
/******************************************************************************
* FunctionName : i2c_master_stop
* Description : set i2c to stop sending state
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_stop(void)
{
// ETS_INTR_UNLOCK();
i2c_master_wait(5);
i2c_master_setDC(0, m_nLastSCL);
i2c_master_wait(5); // sda 0
i2c_master_setDC(0, 1);
i2c_master_wait(5); // sda 0, scl 1
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
// ETS_INTR_UNLOCK();
}
/******************************************************************************
* FunctionName : i2c_master_setAck
* Description : set ack to i2c bus as level value
* Parameters : uint8_t level - 0 or 1
* Returns : NONE
*******************************************************************************/
void i2c_master_setAck(uint8_t level)
{
// ETS_INTR_UNLOCK();
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
i2c_master_setDC(level, 0);
i2c_master_wait(5); // sda level, scl 0
i2c_master_setDC(level, 1);
i2c_master_wait(8); // sda level, scl 1
i2c_master_setDC(level, 0);
i2c_master_wait(5); // sda level, scl 0
i2c_master_setDC(1, 0);
i2c_master_wait(5);
// ETS_INTR_UNLOCK();
}
/******************************************************************************
* FunctionName : i2c_master_getAck
* Description : confirm if peer send ack
* Parameters : NONE
* Returns : uint8_t - ack value, 0 or 1
*******************************************************************************/
uint8_t i2c_master_getAck(void)
{
uint8_t retVal;
// ETS_INTR_UNLOCK();
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5);
i2c_master_setDC(1, 1);
i2c_master_wait(5);
retVal = i2c_master_getDC();
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5);
// ETS_INTR_UNLOCK();
return retVal;
}
/******************************************************************************
* FunctionName : i2c_master_checkAck
* Description : get dev response
* Parameters : NONE
* Returns : true : get ack ; false : get nack
*******************************************************************************/
bool i2c_master_checkAck(void)
{
if(i2c_master_getAck()){
return false;
}else{
return true;
}
}
/******************************************************************************
* FunctionName : i2c_master_send_ack
* Description : response ack
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_send_ack(void)
{
i2c_master_setAck(0x0);
}
/******************************************************************************
* FunctionName : i2c_master_send_nack
* Description : response nack
* Parameters : NONE
* Returns : NONE
*******************************************************************************/
void i2c_master_send_nack(void)
{
i2c_master_setAck(0x1);
}
/******************************************************************************
* FunctionName : i2c_master_readByte
* Description : read Byte from i2c bus
* Parameters : NONE
* Returns : uint8_t - readed value
*******************************************************************************/
uint8_t i2c_master_readByte(void)
{
uint8_t retVal = 0;
uint8_t k, i;
// ETS_INTR_UNLOCK();
i2c_master_wait(5);
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5); // sda 1, scl 0
for (i = 0; i < 8; i++) {
i2c_master_wait(5);
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
i2c_master_setDC(1, 1);
i2c_master_wait(5); // sda 1, scl 1
k = i2c_master_getDC();
i2c_master_wait(5);
if (i == 7) {
i2c_master_wait(3); ////
}
k <<= (7 - i);
retVal |= k;
}
i2c_master_setDC(1, 0);
i2c_master_wait(5); // sda 1, scl 0
// ETS_INTR_UNLOCK();
return retVal;
}
#define DBG_TONY ets_printf
/******************************************************************************
* FunctionName : i2c_master_writeByte
* Description : write wrdata value(one byte) into i2c
* Parameters : uint8_t wrdata - write value
* Returns : NONE
*******************************************************************************/
void i2c_master_writeByte(uint8_t wrdata)
{
uint8_t dat;
int8_t i;
i2c_master_wait(5);
i2c_master_setDC(m_nLastSDA, 0);
i2c_master_wait(5);
for (i = 7; i >= 0; i--) {
dat = wrdata >> i;
i2c_master_setDC(dat, 0);
i2c_master_wait(5);
i2c_master_setDC(dat, 1);
i2c_master_wait(5);
if (i == 0) {
i2c_master_wait(3); ////
}
i2c_master_setDC(dat, 0);
i2c_master_wait(5);
}
}

View file

@ -0,0 +1,615 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "i2s.h"
#include <string.h>
#include "rom/ets_sys.h"
#include "esp_intr.h"
#include "soc/gpio_reg.h"
#include "soc/gpio_sig_map.h"
#include "soc/io_mux_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "driver/gpio.h"
#include "stdio.h"
#define I2S_BASE_CLK (80000000L)
#define ABS(x) (((x)>0)?(x):(-(x)))
//*****************************************************************************
//
// Make sure all of the definitions in this header have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Set the interrupt function.
*
*/
static void i2s_intr_func_set(void * isr, i2s_num_t i2sNum)
{
if (I2S_NUM_I2S0 == i2sNum) {
intr_matrix_set(0, ETS_I2S0_INTR_SOURCE, ETS_I2S0_INUM);
ESP_I2S0_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_I2S0_INTR_ENABLE();
} else if (I2S_NUM_I2S1 == i2sNum) {
intr_matrix_set(0, ETS_I2S1_INTR_SOURCE, ETS_I2S1_INUM);
ESP_I2S1_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_I2S1_INTR_ENABLE();
} else {
// To do nothing
}
}
/**
* @brief Get I2S ping buffer address.
*
*/
uint32_t* i2s_dma_ping_buf_get(i2s_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->ping->buffer_addr;
}
/**
* @brief Get I2S pong buffer address.
*
*/
uint32_t* i2s_dma_pong_buf_get(i2s_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->pong->buffer_addr;
}
/**
* @brief Get not working ping-pong buffer address.
*
*/
uint32_t* i2s_dma_status_get(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
{
if ((NULL == obj)
|| (i2sNum > I2S_NUM_MAX)) {
return NULL;
}
if ((I2S_MODE_MASTER_RX == obj->mode)
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
// Data stream receive
if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(I2S_IN_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
} else if ((I2S_MODE_MASTER_TX == obj->mode)
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
// Data stream send
if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(I2S_OUT_EOF_DES_ADDR_REG(i2sNum)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
}
return NULL;
}
/**
* @brief Set the Ping-Pong buffer to the destination
*
*/
void i2s_dma_dest_add_set(i2s_num_t i2sNum, i2s_dma_attr_t *obj)
{
if ((NULL == obj)
|| (i2sNum > I2S_NUM_MAX)) {
return;
}
if ((I2S_MODE_MASTER_RX == obj->mode)
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
SET_PERI_REG_BITS(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_INLINK_ADDR_S);
} else if ((I2S_MODE_MASTER_TX == obj->mode)
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
SET_PERI_REG_BITS(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), I2S_OUTLINK_ADDR_S);
}
}
/**
* @brief Initialize DMA and create a I2S DMA instance
*
*/
int i2s_dma_init(i2s_num_t i2sNum, i2s_dma_attr_t *obj, void *isr)
{
if ((NULL == obj)
|| (i2sNum > I2S_NUM_MAX)) {
return -1;
}
obj->buf = dma_buf_create(obj->buf_size);
if (NULL == obj->buf) {
return -2;
}
if ((I2S_MODE_MASTER_TX == obj->mode)
|| (I2S_MODE_SLAVE_TX == obj->mode)) {
//Reset DMA
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_OUT_RST);
// enable send intr
i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_SEND_DONE);
} else if ((I2S_MODE_MASTER_RX == obj->mode)
|| (I2S_MODE_SLAVE_RX == obj->mode)) {
//Reset DMA
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
CLEAR_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_IN_RST);
SET_PERI_REG_BITS(I2S_RXEOF_NUM_REG(i2sNum), I2S_RX_EOF_NUM, (obj->buf_size / 4), I2S_RX_EOF_NUM_S);
// enable receive intr
i2s_int_enable(i2sNum, I2S_INT_SRC_ONE_BUF_RECV_DONE /*| I2sIntSrc_RxHalfFull |I2sIntSrc_RxFull*/);
}
//Enable and configure DMA
SET_PERI_REG_MASK(I2S_LC_CONF_REG(i2sNum), I2S_CHECK_OWNER | I2S_OUT_EOF_MODE |
I2S_OUT_LOOP_TEST | I2S_IN_LOOP_TEST);
i2s_intr_func_set(isr, i2sNum);
return 0;
}
/**
* @brief Destroy the I2S DMA instance
*
*/
esp_err_t i2s_dma_uninit(i2s_dma_attr_t *obj)
{
if (NULL == obj) {
return ESP_FAIL;
}
dma_buf_destroy(obj->buf);
return ESP_OK;
}
/**
* @brief Enable the I2S DMA work mode.
*
*/
void i2s_dma_enable(i2s_num_t i2sNum, i2s_mode_t mode)
{
if (i2sNum > I2S_NUM_MAX) {
return;
}
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_START);
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_START);
}
}
/**
* @brief Disable the I2S DMA work mode.
*
*/
void i2s_dma_disable(i2s_num_t i2sNum, i2s_mode_t mode)
{
if (i2sNum > I2S_NUM_MAX) {
return;
}
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
SET_PERI_REG_MASK(I2S_IN_LINK_REG(i2sNum), I2S_INLINK_STOP);
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
SET_PERI_REG_MASK(I2S_OUT_LINK_REG(i2sNum), I2S_OUTLINK_STOP);
}
}
/**
* @brief Set the I2S sample rate, in HZ
*
*/
void i2s_clk_set(int rate, int bits)
{
uint32_t i2sNum = 0 ;
int bckdiv, factor = 32;
int clkmInteger, clkmDecimals;
float denom = (float)1 / 16;
// BCLK = Fs * bits * 2;
// MCLK = factor * BCLK; m = 2;
// clkm = 160MHz / MCLK;
ets_printf("rate=%d, bits=%d \r\n", rate, bits);
float clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
ets_printf("clkmdiv=%f\r\n", clkmdiv);
if (clkmdiv > 256) {
factor++;
clkmdiv = (float)I2S_BASE_CLK / (rate * factor * bits * 2);
}
ets_printf("clkmdiv=%f\r\n", clkmdiv);
clkmInteger = clkmdiv;
ets_printf("clkmInteger=%d\r\n", clkmInteger);
clkmDecimals = (clkmdiv - clkmInteger) / denom;
ets_printf("clkmDecimals=%d\r\n", clkmDecimals);
float mclk = clkmInteger + denom * clkmDecimals;
ets_printf("MCLK=%f\r\n", (float)I2S_BASE_CLK / mclk);
rtc_plla_ena(1,10,2);
#if 0
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
| I2S_CLKM_DIV_A_M
| I2S_CLKM_DIV_B_M));
SET_PERI_REG_MASK(I2S_CLKM_CONF_REG, I2S_CLK_EN | ((0 & I2S_CLKM_DIV_A_V) << I2S_CLKM_DIV_A_S)
| ((0) << I2S_CLKM_DIV_B_S) | (20 & I2S_CLKM_DIV_NUM_V));
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
SET_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, ((4 & I2S_RX_BCK_DIV_NUM_V) << I2S_RX_BCK_DIV_NUM_S)
| ((4 & I2S_TX_BCK_DIV_NUM_V) << I2S_TX_BCK_DIV_NUM_S));
#else
#if 0 // Fs= 48kHz
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
| I2S_CLKM_DIV_A_M
| I2S_CLKM_DIV_B_M));
I2S_SET_CLKA_ENA(1);
I2S_SET_CLKM_DIV_A(63);
I2S_SET_CLKM_DIV_B(32);
I2S_SET_CLKM_DIV_NUM(6);
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
I2S_SET_RX_BCK_DIV_NUM(4);
I2S_SET_TX_BCK_DIV_NUM(2);
I2S_SET_TX_PDM_FS(480);
#else
// Fs = 44.1kHz
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M | I2S_CLKM_DIV_A_M | I2S_CLKM_DIV_B_M));
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_A_V, 64, I2S_CLKM_DIV_A_S);
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_B_V,8, I2S_CLKM_DIV_B_S);
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKM_DIV_NUM_V, 78, I2S_CLKM_DIV_NUM_S);
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M | I2S_TX_BCK_DIV_NUM_M);
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_V, 4, I2S_RX_BCK_DIV_NUM_S);
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BCK_DIV_NUM_V, 2, I2S_TX_BCK_DIV_NUM_S);
SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum), I2S_TX_PDM_FS_V, 441, I2S_TX_PDM_FS_S);
#endif
#endif
CLEAR_PERI_REG_MASK(0x60009000, (0xf));
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), 0x0f);
#if 0 // Fs= 48kHz
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG, (I2S_CLKM_DIV_NUM_M
|I2S_CLKM_DIV_A_M
|I2S_CLKM_DIV_B_M));
I2S_SET_CLKA_ENA(1);
I2S_SET_CLKM_DIV_A(63);
I2S_SET_CLKM_DIV_B(32);
I2S_SET_CLKM_DIV_NUM(6);
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG, I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
I2S_SET_RX_BCK_DIV_NUM(4);
I2S_SET_TX_BCK_DIV_NUM(2);
I2S_SET_TX_PDM_FS(480);
#else
// Fs = 44.1kHz
CLEAR_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), (I2S_CLKM_DIV_NUM_M
|I2S_CLKM_DIV_A_M
|I2S_CLKM_DIV_B_M));
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_A_V,64,I2S_CLKM_DIV_A_S);
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_B_V,8,I2S_CLKM_DIV_B_S);
SET_PERI_REG_BITS(I2S_CLKM_CONF_REG(i2sNum),I2S_CLKM_DIV_NUM_V,78,I2S_CLKM_DIV_NUM_S);
CLEAR_PERI_REG_MASK(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BCK_DIV_NUM_M |I2S_TX_BCK_DIV_NUM_M);
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_RX_BCK_DIV_NUM_V,4,I2S_RX_BCK_DIV_NUM_S);
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum),I2S_TX_BCK_DIV_NUM_V,8,I2S_TX_BCK_DIV_NUM_S);
SET_PERI_REG_BITS(I2S_PDM_FREQ_CONF_REG(i2sNum),I2S_TX_PDM_FS_V,441,I2S_TX_PDM_FS_S);
#endif
CLEAR_PERI_REG_MASK(0x60009000,(0xf));
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum),0x0f);
}
/**
* @brief Reset I2s with a given module.
*
*/
void i2s_reset(i2s_num_t i2sNum)
{
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_RESET_M);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_RESET_M);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_FIFO_RESET_M);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_FIFO_RESET_M);
}
/**
* @brief Initialize the I2S module
*
*/
void i2s_init(i2s_num_t i2sNum, i2s_attr_t *pAttr)
{
if ((i2sNum > I2S_NUM_MAX)
|| (NULL == pAttr)) {
return ;
}
if (i2sNum == I2S_NUM_I2S0) {
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S0_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S0_RST);
} else if (i2sNum == I2S_NUM_I2S1) {
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_I2S1_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_I2S1_RST);
}
// configure I2S data port interface.
CLEAR_PERI_REG_MASK(I2S_CONF2_REG(i2sNum), I2S_LCD_EN);
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PCM2PDM_CONV_EN | I2S_PDM2PCM_CONV_EN);
SET_PERI_REG_BITS(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_SOC_CLK_SEL, 0x1, RTC_CNTL_SOC_CLK_SEL_S);
if (0 != pAttr->rx_mode.mode) {
if (I2S_IFACE_TYPE_DMA == pAttr->rx_mode.iface) {
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
} else {
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
}
// Working mode
if (I2S_MODE_MASTER_RX == pAttr->rx_mode.mode) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SLAVE_MOD);
// configure I2S communication standard format
i2s_clk_set(pAttr->rx_mode.rate, pAttr->rx_mode.bits);
} else if (I2S_MODE_SLAVE_RX == pAttr->rx_mode.mode) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SLAVE_MOD);
} else {
// To do nothing.
}
// configure I2S communication standard format
if (I2S_STD_FORMAT_I2S == pAttr->rx_mode.std) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF1_REG(i2sNum), I2S_RX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_MSB == pAttr->rx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_LSB == pAttr->rx_mode.std) {
} else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->rx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_PCM_LONG == pAttr->rx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_SHORT_SYNC);
} else {
// To do nothing.
}
// configure bit width format.
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_RX_BITS_MOD, pAttr->rx_mode.bits, I2S_RX_BITS_MOD_S);
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_FORCE_EN);
// setting channel mode.
if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->rx_mode.channel) {
// set rx,tx channel mode, both are "two channel" here
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_RX_CHAN_MOD_S);// 0-two channel;1-right;2-left
} else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->rx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_RX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->rx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 0, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_RX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->rx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 1, I2S_RX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->rx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_RX_FIFO_MOD_V, 1, I2S_RX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_RX_CHAN_MOD, 2, I2S_RX_CHAN_MOD_S);
} else {
// To do nothing.
}
if (I2S_MODULE_WORK_TYPE_PDM == pAttr->rx_mode.type) {
if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->rx_mode.ratio) {
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
} else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->rx_mode.ratio) {
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_SINC_DSR_16_EN); // Clear:64*fs;set:128*fs
}
if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
} else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
}
}
}
if (0 != pAttr->tx_mode.mode) {
if (I2S_IFACE_TYPE_DMA == pAttr->tx_mode.iface) {
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
} else {
CLEAR_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_DSCR_EN);
}
if (I2S_MODE_MASTER_TX == pAttr->tx_mode.mode) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SLAVE_MOD);
// configure I2S communication standard format
i2s_clk_set(pAttr->tx_mode.rate, pAttr->tx_mode.bits);
// rtc_plla_ena(1, 621, 14);
// SET_PERI_REG_MASK(I2S_CLKM_CONF_REG(i2sNum), I2S_CLKA_ENA);
printf("rtc_plla_ena is ok\r\n");
} else if (I2S_MODE_SLAVE_RX == pAttr->tx_mode.mode) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SLAVE_MOD);
} else {
// To do nothing.
}
// configure I2S communication standard format
if (I2S_STD_FORMAT_I2S == pAttr->tx_mode.std) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_MSB == pAttr->tx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_LSB == pAttr->tx_mode.std) {
} else if (I2S_STD_FORMAT_PCM_SHORT == pAttr->tx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
} else if (I2S_STD_FORMAT_PCM_LONG == pAttr->tx_mode.std) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_MSB_SHIFT);
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_SHORT_SYNC);
} else {
// To do nothing.
}
// configure bit width format.
SET_PERI_REG_BITS(I2S_SAMPLE_RATE_CONF_REG(i2sNum), I2S_TX_BITS_MOD, pAttr->tx_mode.bits, I2S_TX_BITS_MOD_S);
SET_PERI_REG_MASK(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_FORCE_EN);
if (I2S_CHANNEL_FMT_RIGHT_LEFT == pAttr->tx_mode.channel) {
// set rx,tx channel mode, both are "two channel" here
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_RIGHT_LEFT, I2S_TX_CHAN_MOD_S);// 0-two channel;1-right;2-left
} else if (I2S_CHANNEL_FMT_ALL_RIGHT == pAttr->tx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_RIGHT, I2S_TX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ALL_LEFT == pAttr->tx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 0, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, I2S_CHANNEL_FMT_ALL_LEFT, I2S_TX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ONLY_RIGHT == pAttr->tx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 1, I2S_TX_CHAN_MOD_S);
} else if (I2S_CHANNEL_FMT_ONLY_LEFT == pAttr->tx_mode.channel) {
SET_PERI_REG_BITS(I2S_FIFO_CONF_REG(i2sNum), I2S_TX_FIFO_MOD_V, 1, I2S_TX_FIFO_MOD_S); // 0-right&left channel;1-one channel
SET_PERI_REG_BITS(I2S_CONF_CHAN_REG(i2sNum), I2S_TX_CHAN_MOD, 2, I2S_TX_CHAN_MOD_S);
} else {
// To do nothing.
}
if (I2S_MODULE_WORK_TYPE_PDM == pAttr->tx_mode.type) {
if (PDM_SAMPLE_RATE_RATIO_64 == pAttr->tx_mode.ratio) {
SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 1, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
} else if (PDM_SAMPLE_RATE_RATIO_128 == pAttr->tx_mode.ratio) {
SET_PERI_REG_BITS(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_SINC_OSR2_M, 2, I2S_TX_PDM_SINC_OSR2_S); // TX: 2---128*fs;1---64*fs
}
if (PDM_PCM_CONV_ENABLE == pAttr->rx_mode.conv) {
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
} else if (PDM_PCM_CONV_DISABLE == pAttr->rx_mode.conv) {
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_PDM2PCM_CONV_EN);
}
}
}
// Clear all of the interrupt sources.
WRITE_PERI_REG(I2S_INT_CLR_REG(i2sNum), 0xffffffff);
}
/**
* @brief Enable the interrupt source.
*
*/
void i2s_int_enable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
{
SET_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
}
/**
* @brief Disable the interrupt source.
*
*/
void i2s_int_disable(i2s_num_t i2sNum, i2s_int_src_t intSrc)
{
CLEAR_PERI_REG_MASK(I2S_INT_ENA_REG(i2sNum), intSrc);
}
/**
* @brief Clear the interrupt source.
*
*/
void i2s_int_clear(i2s_num_t i2sNum, i2s_int_src_t intSrc)
{
SET_PERI_REG_MASK(I2S_INT_CLR_REG(i2sNum), intSrc);
}
/**
* @brief Get the I2S interrupt status
*/
uint32_t i2s_int_status_get(i2s_num_t i2sNum)
{
return READ_PERI_REG(I2S_INT_ST_REG(i2sNum));
}
/**
* @brief Start I2S work
*
*/
void i2s_start(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
{
if (i2sNum > I2S_NUM_MAX) {
return;
}
if (I2S_MODULE_WORK_TYPE_I2S == type) {
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
}
} else if (I2S_MODULE_WORK_TYPE_PDM == type) {
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
SET_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
SET_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
}
}
}
/**
* @brief Stop I2S work
*
*/
void i2s_stop(i2s_module_work_type_t type, i2s_num_t i2sNum, i2s_mode_t mode)
{
if (i2sNum > I2S_NUM_MAX) {
return;
}
if (I2S_MODULE_WORK_TYPE_I2S == type) {
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
SET_PERI_REG_MASK(GPIO_ENABLE_REG, BIT(0));
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
}
} else if (I2S_MODULE_WORK_TYPE_PDM == type) {
if ((I2S_MODE_MASTER_RX == mode)
|| (I2S_MODE_SLAVE_RX == mode)) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_RX_START);
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_RX_PDM_EN);
} else if ((I2S_MODE_MASTER_TX == mode)
|| (I2S_MODE_SLAVE_TX == mode)) {
CLEAR_PERI_REG_MASK(I2S_CONF_REG(i2sNum), I2S_TX_START);
CLEAR_PERI_REG_MASK(I2S_PDM_CONF_REG(i2sNum), I2S_TX_PDM_EN);
}
}
}
#ifdef __cplusplus
}
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,827 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "spi.h"
#include "soc/spi_reg.h"
#include "soc/rtc_cntl_reg.h"
#include "rom/ets_sys.h"
#include "esp_intr.h"
#include "soc/dport_reg.h"
//*****************************************************************************
//
// Make sure all of the definitions in this header have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
/**
* @brief Defines slave commands.Default value based on slave ESP8266 & ESP32.
*/
#define MASTER_WRITE_DATA_TO_SLAVE_CMD 2
#define MASTER_READ_DATA_FROM_SLAVE_CMD 3
#define MASTER_WRITE_STATUS_TO_SLAVE_CMD 1
#define MASTER_READ_STATUS_FROM_SLAVE_CMD 4
static void spi_intr_func_set(void * isr, spi_num_t spiNum)
{
if (SPI_NUM_SPI1 == spiNum) {
intr_matrix_set(0, ETS_SPI1_DMA_INTR_SOURCE, ETS_SPI1_INUM);
ESP_SPI1_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI1_INTR_ENABLE();
} else if (SPI_NUM_SPI2 == spiNum) {
intr_matrix_set(0, ETS_SPI2_DMA_INTR_SOURCE, ETS_SPI2_INUM);
ESP_SPI2_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI2_INTR_ENABLE();
} else if (SPI_NUM_SPI3 == spiNum) {
intr_matrix_set(0, ETS_SPI3_DMA_INTR_SOURCE, ETS_SPI3_INUM);
ESP_SPI3_INTR_ATTACH(isr, NULL);
// enable intr in cpu
ESP_SPI3_INTR_ENABLE();
} else {
// To do nothing
}
}
#if 1
/**
* @brief Get SPI ping buffer address.
*
*/
uint32_t* spi_dma_ping_buf_get(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->ping->buffer_addr;
}
/**
* @brief Get SPI ping buffer address.
*
*/
uint32_t* spi_dma_pong_buf_get(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return NULL;
}
return obj->buf->pong->buffer_addr;
}
/**
* @brief Get without work ping-pong buffer address.
*
*/
uint32_t* spi_dma_status_get(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return NULL;
}
switch (obj->dir) {
case SPI_DMA_DIR_OUT:
if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(SPI_OUT_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
break;
case SPI_DMA_DIR_IN:
if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->ping->last_queue)) {
return obj->buf->ping->buffer_addr;
} else if (READ_PERI_REG(SPI_IN_SUC_EOF_DES_ADDR_REG(obj->spi_num)) == ((uint32_t)obj->buf->pong->last_queue)) {
return obj->buf->pong->buffer_addr;
}
break;
default:
break;
}
return NULL;
}
/**
* @brief Configrate the Ping-Pong buffer to the destination
*
*/
void spi_dma_dest_add_set(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
SET_PERI_REG_BITS(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_INLINK_ADDR_S);
} else if (SPI_DMA_DIR_OUT == obj->dir) {
SET_PERI_REG_BITS(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_ADDR, ((uint32_t)(obj->buf->ping->first_queue)), SPI_OUTLINK_ADDR_S);
}
}
/**
* @brief Reset SPI ping buffer address.
*
*/
void spi_dma_rest(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
dma_buf_len_reset(obj->buf);
}
/**
* @brief Initialize DMA and create a SPI DMA instance.
*
*/
int spi_dma_init(spi_dma_attr_t *obj, void *isr)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return -1;
}
obj->buf = dma_buf_create(obj->buf_size);
if (NULL == obj->buf) {
return -2;
}
// Reset DMA
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
// Select DMA channel.
SET_PERI_REG_BITS(DPORT_SPI_DMA_CHAN_SEL_REG, 3, obj->channel, ((obj->spi_num - 1) * 2));
SET_PERI_REG_MASK(SPI_USER_REG(obj->spi_num), SPI_USR_MOSI);//////add
if ((SPI_MODE_MASTER == obj->mode)) {
// enable send intr
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_SEND_DONE);
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num ), SPI_INT_SRC_ONE_BUF_RECV_DONE);
} else if ((SPI_MODE_SLAVE == obj->mode)) {
SET_PERI_REG_MASK(SPI_SLV_RDBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
SET_PERI_REG_MASK(SPI_SLV_WRBUF_DLEN_REG(obj->spi_num), ((obj->buf_size << 3) - 1));
// enable receive intr
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(obj->spi_num), SPI_INT_SRC_ONE_BUF_RECV_DONE);
}
// Clear all of interrupt source
spi_int_clear(obj->spi_num);
spi_intr_func_set(isr, obj->spi_num);
return 0;
}
/**
* @brief Destroy the SPI DMA instance
*
*/
int spi_dma_uninit(spi_dma_attr_t *obj)
{
if (NULL == obj) {
return -1;
}
dma_buf_destroy(obj->buf);
return 0;
}
/**
* @brief Enable the SPI DMA work mode.
*
*/
static void spi_dma_enable(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
WRITE_PERI_REG(0x3ff000c4,1<<22);
WRITE_PERI_REG(0x3ff000c4,0);
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
// LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
// while (((READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18)&0x3)!=0x3){
//LOGD("recv-01:length=%x",READ_PERI_REG(SPI_DMA_TSTATUS_REG(obj->spi_num))>>18);
// }
} else if (SPI_DMA_DIR_OUT == obj->dir) {
SET_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_START);
SET_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_START);
// Waiting DMA controller fill TX FIFO
while ((READ_PERI_REG(SPI_DMA_RSTATUS_REG(obj->spi_num))&0x80000000));
}
}
/**
* @brief Disable the SPI DMA work mode.
*
*/
static void spi_dma_disable(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_DMA_DIR_IN == obj->dir) {
CLEAR_PERI_REG_MASK(SPI_DMA_IN_LINK_REG(obj->spi_num), SPI_INLINK_STOP);
} else if (SPI_DMA_DIR_OUT == obj->dir) {
CLEAR_PERI_REG_MASK(SPI_DMA_OUT_LINK_REG(obj->spi_num), SPI_OUTLINK_STOP);
}
}
/**
* @brief Enable SPI DMA interrupt source.
*
*/
void spi_dma_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
}
/**
* @brief Disable SPI DMA interrupt source.
*
*/
void spi_dma_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_ENA_REG(spiNum), intSrc);
}
/**
* @brief Clear all of SPI DMA interrupt source.
*
*/
void spi_dma_int_clear(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_DMA_INT_CLR_REG(spiNum), 0x1FF);
}
/**
* @brief Get the SPI DMA interrupt status.
*
*/
int32_t spi_dma_int_status_get(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return -1;
}
return READ_PERI_REG(SPI_DMA_INT_ST_REG(spiNum));
}
/**
* @brief Start SPI work by DMA
*
*/
void spi_dma_start(spi_dma_attr_t *obj, uint32_t len)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
// Reset DMA controller
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_OUT_RST | SPI_IN_RST | SPI_AHBM_RST | SPI_AHBM_FIFO_RST);
if (SPI_MODE_MASTER == obj->mode) {
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
if (obj->dir == SPI_DMA_DIR_IN) {
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
}else{
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(obj->spi_num), SPI_USR_MISO_DBITLEN, ((len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(obj->spi_num), SPI_USR_MOSI_DBITLEN, ((len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
}
} else if (SPI_MODE_SLAVE == obj->mode) {
if (0 == len) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
} else {
CLEAR_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_CONTINUE);
}
}
// 1.Enable DMA
spi_dma_enable(obj);
//LOGD("recv start before:%08x\n",obj->buf->ping->first_queue->data_length);
// LOGD("SPI_DMA_STATUS_REG=%x",READ_PERI_REG(SPI_DMA_STATUS_REG(obj->spi_num)));
// 2.Start SPI
SET_PERI_REG_MASK(SPI_CMD_REG(obj->spi_num), SPI_USR);
//LOGD("recv start after:%08x\n",obj->buf->ping->first_queue->data_length);
}
/**
* @brief Stop SPI work by DMA
*
*/
void spi_dma_stop(spi_dma_attr_t *obj)
{
if ((NULL == obj)
|| (obj->spi_num > SPI_NUM_MAX)) {
return;
}
if (SPI_MODE_MASTER == obj->mode) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_TX_STOP);
} else if (SPI_MODE_SLAVE == obj->mode) {
SET_PERI_REG_MASK(SPI_DMA_CONF_REG(obj->spi_num), SPI_DMA_RX_STOP);
}
spi_dma_disable(obj);
}
#endif
/**
* @brief Based on pAttr initialize SPI module.
*
*/
void spi_init(spi_num_t spiNum, spi_attr_t* pAttr)
{
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pAttr)) {
return;
}
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST);
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_1);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_1);
SET_PERI_REG_MASK(DPORT_PERIP_CLK_EN_REG, DPORT_SPI_CLK_EN_2);
CLEAR_PERI_REG_MASK(DPORT_PERIP_RST_EN_REG, DPORT_SPI_RST_2);
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE << 5);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);
// By default clear command
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// SPI_CPOL & SPI_CPHA
switch (pAttr->sub_mode) {
case SPI_SUBMODE_1:
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
break;
case SPI_SUBMODE_2:
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE); // CHPA_FALLING_EDGE_SAMPLE
break;
case SPI_SUBMODE_3:
SET_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
break;
case SPI_SUBMODE_0:
default:
CLEAR_PERI_REG_MASK(SPI_PIN_REG(spiNum), SPI_CK_IDLE_EDGE);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CK_OUT_EDGE);
// To do nothing
break;
}
// SPI bit order
if (SPI_BIT_ORDER_MSB_FIRST == pAttr->bit_order) {
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
CLEAR_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
} else if (SPI_BIT_ORDER_LSB_FIRST == pAttr->bit_order) {
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_WR_BIT_ORDER);
SET_PERI_REG_MASK(SPI_CTRL_REG(spiNum), SPI_RD_BIT_ORDER);
} else {
// To do nothing
}
// SPI bit order
if (SPI_WORK_MODE_HALF == pAttr->half_mode) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
} else if (SPI_WORK_MODE_FULL == pAttr->half_mode) {
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_DOUTDIN);
}
// May be not must to do.
WRITE_PERI_REG(SPI_USER1_REG(spiNum), 0);
// SPI mode type
if (SPI_MODE_MASTER == pAttr->mode) {
// SPI mode type
SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_MODE, 0, SPI_MISO_DELAY_MODE_S); ////??????
// SPI_SET_MISO_DELAY_NUM(spiNum,0);////???????
//SET_PERI_REG_BITS(SPI_CTRL2_REG(spiNum), SPI_MISO_DELAY_NUM,0,SPI_MISO_DELAY_NUM_S);////??????
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
// SPI Send buffer
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART );// By default slave send buffer C0-C7
// SPI Speed
if (1 < (pAttr->speed)) {
uint8_t i, k;
i = (pAttr->speed / 40) ? (pAttr->speed / 40) : 1;
k = pAttr->speed / i;
CLEAR_PERI_REG_MASK(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK);
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum),
(((i - 1) & SPI_CLKDIV_PRE) << SPI_CLKDIV_PRE_S) |
(((k - 1) & SPI_CLKCNT_N) << SPI_CLKCNT_N_S) |
((((k + 1) / 2 - 1) & SPI_CLKCNT_H) << SPI_CLKCNT_H_S) |
(((k - 1) & SPI_CLKCNT_L) << SPI_CLKCNT_L_S)); //clear bit 31,set SPI clock div
} else {
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), SPI_CLK_EQU_SYSCLK); // 80Mhz speed
}
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP | SPI_CS_HOLD | SPI_USR_MOSI);
// CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_HOLD);/////////////add
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x4 & SPI_MISO_DELAY_NUM) << SPI_MISO_DELAY_NUM_S)); //delay num
} else if (SPI_MODE_SLAVE == pAttr->mode) {
// SPI mode type
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLAVE_MODE);
// SPI mode type
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_SLV_WR_RD_BUF_EN);
// SPI Send buffer
// SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO_HIGHPART);// By default slave send buffer C8-C15
// If do not set delay cycles, slave not working,master cann't get the data.
SET_PERI_REG_MASK(SPI_CTRL2_REG(spiNum), ((0x2 & SPI_MOSI_DELAY_NUM) << SPI_MOSI_DELAY_NUM_S)); //delay num
// SPI Speed
WRITE_PERI_REG(SPI_CLOCK_REG(spiNum), 0);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_CS_SETUP);/////////////add
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// By default format::CMD(8bits)+ADDR(8bits)+DATA(32bytes)
// set pAttr->cmd_len bit slave recieve command length
// set 1 bytes status buffer length
// set pAttr->addr_len bit slave recieve read address length
// set pAttr->addr_len bit slave recieve write address length
// set 32 bytes slave recieve buffer length
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
(7), SPI_USR_COMMAND_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_STATUS_BITLEN,
(7), SPI_SLV_STATUS_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_WR_ADDR_BITLEN,
(7), SPI_SLV_WR_ADDR_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLAVE1_REG(spiNum), SPI_SLV_RD_ADDR_BITLEN,
(7), SPI_SLV_RD_ADDR_BITLEN_S);
SET_PERI_REG_BITS(SPI_SLV_WRBUF_DLEN_REG(spiNum), SPI_SLV_WRBUF_DBITLEN,
(32 * 8 - 1), SPI_SLV_WRBUF_DBITLEN_S);
SET_PERI_REG_BITS(SPI_SLV_RDBUF_DLEN_REG(spiNum), SPI_SLV_RDBUF_DBITLEN,
(32 * 8 - 1), SPI_SLV_RDBUF_DBITLEN_S);
} else {
// To do nothing
}
char i;
for (i = 0; i < 16; ++i) {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), 0);
}
}
/**
* @brief Set address value by master mode.
*
*/
void spi_master_cfg_addr(spi_num_t spiNum, uint32_t addr)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
// Set address
SET_PERI_REG_BITS(SPI_ADDR_REG(spiNum), SPI_USR_ADDR_VALUE, addr, SPI_USR_ADDR_VALUE_S);
}
/**
* @brief Set command value by master mode.
*
*/
void spi_master_cfg_cmd(spi_num_t spiNum, uint32_t cmd)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
// SPI_USER2 bit28-31 is cmd length,cmd bit length is value(0-15)+1,
// bit15-0 is cmd value.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_VALUE, cmd, SPI_USR_COMMAND_VALUE_S);
}
/**
* @brief Send data to slave.
*
*/
int spi_master_send_data(spi_num_t spiNum, spi_data_t* pInData)
{
char idx = 0;
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pInData)
|| (64 < pInData->tx_data_len)) {
return -1;
}
uint32_t *value = pInData->tx_data;
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Set command by user.
if (pInData->cmd_len != 0) {
// Max command length 16 bits.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
((pInData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
// Enable command
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// Load command
spi_master_cfg_cmd(spiNum, pInData->cmd);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
0, SPI_USR_COMMAND_BITLEN_S);
}
// Set Address by user.
if (pInData->addr_len == 0) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
0, SPI_USR_ADDR_BITLEN_S);
} else {
if (NULL == pInData->addr) {
return -1;
}
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
((pInData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
// Enable address
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
// Load address
spi_master_cfg_addr(spiNum, *pInData->addr);
}
// Set data by user.
if (pInData->tx_data_len != 0) {
if (NULL == value) {
return -1;
}
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// Load send buffer
do {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (idx << 2)), *value++);
} while (++idx < ((pInData->tx_data_len / 4) + ((pInData->tx_data_len % 4) ? 1 : 0)));
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN, ((pInData->tx_data_len << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pInData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
0, SPI_USR_MOSI_DBITLEN_S);
}
// Start send data
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (!(READ_PERI_REG(SPI_SLAVE_REG(spiNum))&SPI_TRANS_DONE));
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_TRANS_DONE);
return 0;
}
/**
* @brief Receive data from slave.
*
*/
int spi_master_recv_data(spi_num_t spiNum, spi_data_t* pData)
{
char idx = 0;
if ((spiNum > SPI_NUM_MAX)
|| (NULL == pData)) {
return -1;
}
uint32_t *value = pData->rx_data;
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Set command by user.
if (pData->cmd_len != 0) {
// Max command length 16 bits.
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
((pData->cmd_len << 3) - 1), SPI_USR_COMMAND_BITLEN_S);
// Enable command
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
// Load command
spi_master_cfg_cmd(spiNum, pData->cmd);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_COMMAND);
SET_PERI_REG_BITS(SPI_USER2_REG(spiNum), SPI_USR_COMMAND_BITLEN,
0, SPI_USR_COMMAND_BITLEN_S);
}
// Set Address by user.
if (pData->addr_len == 0) {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
0, SPI_USR_ADDR_BITLEN_S);
} else {
if (NULL == pData->addr) {
return -1;
}
SET_PERI_REG_BITS(SPI_USER1_REG(spiNum), SPI_USR_ADDR_BITLEN,
((pData->addr_len << 3) - 1), SPI_USR_ADDR_BITLEN_S);
// Enable address
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_ADDR);
// Load address
spi_master_cfg_addr(spiNum, *pData->addr);
}
// Set data by user.
if (pData->rx_data_len != 0) {
if (NULL == value) {
return -1;
}
// Clear MOSI enable
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
// Enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
// Set data send buffer length.Max data length 64 bytes.
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, ((pData->rx_data_len << 3) - 1), SPI_USR_MISO_DBITLEN_S);
} else {
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN, 0, SPI_USR_MISO_DBITLEN_S);
}
// Start send data
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// Read data out
do {
*value++ = READ_PERI_REG(SPI_W0_REG(spiNum) + (idx << 2));
} while (++idx < ((pData->rx_data_len / 4) + ((pData->rx_data_len % 4) ? 1 : 0)));
return 0;
}
/**
* @brief Load data to send buffer by slave mode.
*
*/
int spi_slave_send_data(spi_num_t spiNum, uint32_t *pOutData, uint8_t outLen)
{
if (NULL == pOutData) {
return -1;
}
char i;
uint32_t *value = pOutData;
for (i = 0; i < outLen; ++i) {
WRITE_PERI_REG((SPI_W0_REG(spiNum) + (i << 2)), *value++);
}
return 0;
}
/**
* @brief Configurate slave prepare for receive data.
*
*/
int spi_slave_recv_data(spi_num_t spiNum, void(*isrFunc)(void*))
{
char idx = 0;
if (spiNum > SPI_NUM_MAX) {
return -1;
}
spi_int_enable(spiNum, SPI_INT_SRC_WR_STA_DONE
| SPI_INT_SRC_RD_STA_DONE | SPI_INT_SRC_WR_BUF_DONE | SPI_INT_SRC_RD_BUF_DONE);
spi_int_disable(spiNum, SPI_INT_SRC_TRANS_DONE);
spi_intr_func_set(isrFunc, spiNum);
return 0;
}
/**
* @brief Send data to slave(ESP32,RD_STATUS or WR_STATUS).
*
*/
void spi_master_send_status(spi_num_t spiNum, uint8_t data)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// enable MOSI
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO | SPI_USR_DUMMY | SPI_USR_ADDR);
// 8bits cmd, 0x04 is eps32 slave write cmd value
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
| MASTER_WRITE_STATUS_TO_SLAVE_CMD);
// Set data send buffer length.
SET_PERI_REG_BITS(SPI_MOSI_DLEN_REG(spiNum), SPI_USR_MOSI_DBITLEN,
((sizeof(data) << 3) - 1), SPI_USR_MOSI_DBITLEN_S);
WRITE_PERI_REG(SPI_W0_REG(spiNum), (uint32_t)(data));
// start SPI
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
}
/**
* @brief Receive data from slave(ESP32).
*
*/
int spi_master_recv_status(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return -1;
}
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
// enable MISO
SET_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MISO);
CLEAR_PERI_REG_MASK(SPI_USER_REG(spiNum), SPI_USR_MOSI | SPI_USR_DUMMY | SPI_USR_ADDR);
// 8bits cmd, 0x06 is eps32 slave read cmd value
WRITE_PERI_REG(SPI_USER2_REG(spiNum),
((7 & SPI_USR_COMMAND_BITLEN) << SPI_USR_COMMAND_BITLEN_S)
| MASTER_READ_STATUS_FROM_SLAVE_CMD);
// Set revcive buffer length.
SET_PERI_REG_BITS(SPI_MISO_DLEN_REG(spiNum), SPI_USR_MISO_DBITLEN,
7, SPI_USR_MISO_DBITLEN_S);
// start spi module.
SET_PERI_REG_MASK(SPI_CMD_REG(spiNum), SPI_USR);
while (READ_PERI_REG(SPI_CMD_REG(spiNum))&SPI_USR);
uint8_t data = (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
return (uint8_t)(READ_PERI_REG(SPI_W0_REG(spiNum)) & 0xff);
}
/**
* @brief Enable SPI interrupt source.
*
*/
void spi_int_enable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
SET_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc << 4);
}
/**
* @brief Disable SPI interrupt source.
*
*/
void spi_int_disable(spi_num_t spiNum, spi_int_src_t intSrc)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), intSrc);
}
/**
* @brief Clear all of SPI interrupt source.
*
*/
void spi_int_clear(spi_num_t spiNum)
{
if (spiNum > SPI_NUM_MAX) {
return;
}
CLEAR_PERI_REG_MASK(SPI_SLAVE_REG(spiNum), SPI_INT_SRC_TRANS_DONE
| SPI_INT_SRC_WR_STA_DONE
| SPI_INT_SRC_RD_STA_DONE
| SPI_INT_SRC_WR_BUF_DONE
| SPI_INT_SRC_RD_BUF_DONE);
}
/**
* @brief Get the SPI interrupt status.
*
*/
int32_t spi_int_status_get(spi_num_t i2sNum)
{
if (i2sNum > SPI_NUM_MAX) {
return -1;
}
return READ_PERI_REG(SPI_SLAVE_REG(i2sNum));
}
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,469 @@
#include "driver/i2c.h"
#include "esp_types.h"
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/xtensa_api.h"
#include "esp_err.h"
#include "driver/i2c_soft.h"
#include "ES7242.h"
#include "driver/gpio.h"
//#include "driver/gpio_sig_map.h"
#include "rom/ets_sys.h"
#define I2C_FREQ 100000 //HZ
#define I2C_SLAVE_DEV_ADDR 0x60
#define I2C_SDA_OUT_IO_NUM 21
#define I2C_SDA_OUT_IO_SIG I2CEXT0_SDA_OUT_IDX
#define I2C_SDA_OUT_IO_PIN GPIO_SEL_21
#define I2C_SCL_OUT_IO_NUM 19
#define I2C_SCL_OUT_IO_SIG I2CEXT0_SCL_OUT_IDX
#define I2C_SCL_OUT_IO_PIN GPIO_SEL_19
#define I2C_SDA_IN_IO_SIG I2CEXT0_SDA_IN_IDX
#define I2C_SCL_IN_IO_SIG I2CEXT0_SCL_IN_IDX
#define ES8388_ADDR 0x20
#if 0
void I2C_GpioInit()
{
#if 1
ets_printf("Configuring GPIO...........\n");
gpio_config_t gpio_conf;
gpio_conf.gpio_pin_sel = I2C_SDA_OUT_IO_PIN | I2C_SCL_OUT_IO_PIN ;
gpio_conf.gpio_mode_sel = GPIO_MODE_INPUT_OUTPUT_OD;
gpio_conf.gpio_pulldown_sel = GPIO_PULLDOWN_DISABLE;
gpio_conf.gpio_pullup_sel = GPIO_PULLUP_ENABLE;
gpio_conf.gpio_intry_type_sel = GPIO_PIN_INTR_DISABLE;
gpio_config(&gpio_conf);
#if 0
SET_PERI_REG_BITS(GPIO_PIN_REG_19, FUN_DRV, 3, FUN_DRV_S);
SET_PERI_REG_BITS(GPIO_PIN_REG_23, FUN_DRV, 3, FUN_DRV_S);
CLEAR_PERI_REG_MASK(GPIO_PIN_REG_19, FUN_PD);
CLEAR_PERI_REG_MASK(GPIO_PIN_REG_23, FUN_PD);
#endif
gpio_matrix_out(I2C_SDA_OUT_IO_NUM, I2C_SDA_OUT_IO_SIG, 0, 0);
gpio_matrix_out(I2C_SCL_OUT_IO_NUM, I2C_SCL_OUT_IO_SIG, 0, 0);
gpio_matrix_in(I2C_SDA_OUT_IO_NUM, I2C_SDA_IN_IO_SIG, 0);
gpio_matrix_in(I2C_SCL_OUT_IO_NUM, I2C_SCL_IN_IO_SIG, 0);
#else
// SDA OUT
gpio_matrix_out(19, I2C_SDA_OUT_IO_SIG, 0, 0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO19_U, FUNC_GPIO19_GPIO19);
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_IE | FUN_PU);
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO19_U, FUN_PD);
SET_PERI_REG_MASK(GPIO_PIN19_REG, GPIO_PIN19_PAD_DRIVER);
//====debug====
gpio_matrix_out(23, I2C_SCL_OUT_IO_SIG, 0, 0);
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO23_U, FUNC_GPIO23_GPIO23);
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_IE | FUN_PU);
CLEAR_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO23_U, FUN_PD);
SET_PERI_REG_MASK(GPIO_PIN23_REG, GPIO_PIN23_PAD_DRIVER);
//============================
//SDA IN
gpio_matrix_in(19, I2C_SDA_IN_IO_SIG, 0);
//SCL IN
gpio_matrix_in(23, I2C_SCL_IN_IO_SIG, 0);
#endif
ets_printf("GPIO Configured! ! ! ! ! ! ! ! ! !\n");
}
void disp_cmd(uint8_t i2c_no, uint8_t idx)
{
// ets_printf("---cmd %d ---\n",idx);
// ets_printf("opcode: %d \n",I2C_GET_COMMAND_OP_CODE(i2c_no,idx));
// ets_printf("acken: %d \n",I2C_GET_COMMAND_ACK_EN(i2c_no,idx));
// ets_printf("ackexp: %d \n",I2C_GET_COMMAND_ACK_EXP(i2c_no,idx));
// ets_printf("ack val: %d \n",I2C_GET_COMMAND_ACK_VALUE(i2c_no,idx));
// ets_printf("byte num: %d \n",I2C_GET_COMMAND_BYTE_NUM(i2c_no,idx));
// ets_printf("done: %d \n",I2C_GET_COMMAND_DONE(i2c_no,idx));
}
void i2c_master_read_test()
{
uint8_t i2c_no = 0;
uint8_t idx = 0;
uint8_t data_buf[] = {I2C_SLAVE_DEV_ADDR, //addr
0x10,
0x01,
0x12,
0x13,
0x14,
};
uint8_t byte_num = 3;//sizeof(data_buf);
I2C_SET_TX_FIFO_RST(0, 1);
I2C_SET_TX_FIFO_RST(0, 0);
//command0 : sending restart signal
idx = 0;
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0);
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
I2C_SET_COMMAND_BYTE_NUM(i2c_no, 0, 1);
disp_cmd( i2c_no, 0);
//command1 : picking slave and sending data
idx = 1;
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0);
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 1); //WRITE COMMAND
I2C_SET_COMMAND_BYTE_NUM(i2c_no, idx, byte_num); //BYTE NUMBER
disp_cmd( i2c_no, 1);
//command2 : master generating stop
idx = 2;
I2C_SET_COMMAND_OP_CODE(i2c_no, idx, 0x3); //STOP
I2C_SET_COMMAND_ACK_EN(i2c_no, idx, 0); //NO ACK
disp_cmd( i2c_no, 2);
int i = 0;
for (i = 0; i < byte_num; i++) {
WRITE_PERI_REG(I2C_DATA_REG(i2c_no), data_buf[i]);
}
//start sending
I2C_SET_TRANS_START(i2c_no, 1);
}
void I2C_MasterInit(uint8_t init_num)
{
//step 1: gpio init
I2C_GpioInit();
#if 1
ets_delay_us(500000);
//step 2: i2c init
ets_printf("Initializing I2C Master.............\r\n");
I2C_InitTypeDef i2c_master;
i2c_master.mode = I2C_MASTER_MODE; //master mode
i2c_master.addr_10bit_en = 0; //not used
i2c_master.clk_speed = 100000; //clk set
i2c_master.slave_addr = 0x0; //no slave addr for master mode
I2C_Init(init_num, &i2c_master);
#else
uint8_t i2c_no = init_num;
if (i2c_no > 1) {
ets_printf("invalid i2c number...\r\n");
return;
}
//set master mode
//I2C_SET_RX_LSB_FIRST(i2c_no,0); //MSB FIRST
//I2C_SET_TX_LSB_FIRST(i2c_no,0); //MSB FIRST
I2C_SET_MS_MODE(i2c_no, 1); //MASTER MODE
//I2C_SET_SCL_FORCE_OUT(i2c_no,1); //out put practical level
//I2C_SET_SDA_FORCE_OUT(i2c_no,1); //out put practical level
//SET FREQ/DUTY
I2C_SET_SCL_LOW_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
I2C_SET_SCL_HIGH_PERIOD(i2c_no, (APB_CLK_FREQ / I2C_FREQ) / 2);
//SET CLK RE/START HOLD/SETUP
I2C_SET_SCL_START_HOLD_TIME(i2c_no, 50); //400);
I2C_SET_SCL_RSTART_SETUP_TIME(i2c_no, 50); //400);
//SET CLK STOP HOLD/SETUP
I2C_SET_SCL_STOP_HOLD_TIME(i2c_no, 50); //400);
I2C_SET_SCL_STOP_SETUP_TIME(i2c_no, 50); //400);
//SET DATA I/O HOLD/SAMPLE
I2C_SET_SDA_HOLD_TIME(i2c_no, 40);
I2C_SET_SDA_SAMPLE_TIME(i2c_no, 40);
//SET CLK TIME OUT
//I2C_SET_TIME_OUT_THRSH(i2c_no,2000);
I2C_SET_TIME_OUT_REG(i2c_no, 2000);
//SET FIFO MODE
//I2C_SET_NONFIFO_EN(i2c_no,0);
//SET SCL FILTER
//I2C_SET_SCL_FILTER_EN(i2c_no,1);
//SET SDA FILTER
//I2C_SET_SDA_FILTER_EN(i2c_no,0);
//i2c_intr_config();
#endif
}
void i2c_send_data_test(uint8_t i2c_num, uint8_t slave_addr, uint8_t reg_addr, uint8_t data)
{
//struct I2C_DEV * I2Cx = I2C(i2c_num);
uint8_t data_buf[] = {
slave_addr,
reg_addr,
data
};
uint8_t byte_num = sizeof(data_buf);
struct I2C_CmdDef cmd;
memset(&cmd, 0, sizeof(cmd));
//reset tx fifo
I2C_ResetTxFifo(i2c_num);
//setup command 0
memset(&cmd, 0, sizeof(cmd));
cmd.ack_en = 0;
cmd.ack_exp = 0;
cmd.ack_val = 0;
cmd.byte_num = 0;
cmd.op_code = I2C_CMD_RESTART;
I2C_ConfigCmd(i2c_num, 0, &cmd);
disp_cmd( i2c_num, 0);
//setup command 1
memset(&cmd, 0, sizeof(cmd));
cmd.ack_en = 0;
cmd.ack_exp = 0;
cmd.ack_val = 0;
cmd.byte_num = byte_num;
cmd.op_code = I2C_CMD_WRITE;
I2C_ConfigCmd(i2c_num, 1, &cmd);
disp_cmd( i2c_num, 1);
//setup command 2
memset(&cmd, 0, sizeof(cmd));
cmd.byte_num = 0;
cmd.op_code = I2C_CMD_STOP;
I2C_ConfigCmd(i2c_num, 2, &cmd);
disp_cmd( i2c_num, 2);
//push the sending data to tx fifo
I2C_TxFifoPush(i2c_num, data_buf , byte_num);
//I2C start sending
I2C_Start(i2c_num);
I2C_WaitTxDone(i2c_num, 2);
}
#endif
void ES8388_PowerOn_Init1(void)
{
ES7242_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07); //PLAY BACK,ENREFR=0 //changed
ES7242_WriteReg(ES8388_ADDR, 0x2d, 0x00); //vroi=0
ets_delay_us(10000);
ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
ets_delay_us(10000);
ES7242_WriteReg(ES8388_ADDR, 0x02, 0xf3); //Reset STM and DLL
ES7242_WriteReg(ES8388_ADDR, 0x03, 0xFF); //Reset STM and DLL
ES7242_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
ES7242_WriteReg(ES8388_ADDR, 0x0A, 0x00); //LIN1/RIN1 as ADC Input
ES7242_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT,LADC=Left data,RADC=right data W
ES7242_WriteReg(ES8388_ADDR, 0x0d, 0x02); //SINGLE SPEED,RATIO=256
ES7242_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC Left Volume=0db
ES7242_WriteReg(ES8388_ADDR, 0x11, 0x00); //ADC Right Volume=0db
ES7242_WriteReg(ES8388_ADDR, 0x17, 0x18); //I2S-16BIT 0x18 //PCM 16BIT 0x5E
ES7242_WriteReg(ES8388_ADDR, 0x18, 0x02); //SINGLE SPEED,RATIO=256
ES7242_WriteReg(ES8388_ADDR, 0x19, 0x36); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
ES7242_WriteReg(ES8388_ADDR, 0x1A, 0x00); //LDAC volume=0db,RDAC Volume=0db
ES7242_WriteReg(ES8388_ADDR, 0x1B, 0x00);
ES7242_WriteReg(ES8388_ADDR, 0x19, 0x32); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
ES7242_WriteReg(ES8388_ADDR, 0x27, 0xB8); //Left DAC TO Left MIXER
ES7242_WriteReg(ES8388_ADDR, 0x28, 0x38);
ES7242_WriteReg(ES8388_ADDR, 0x29, 0x38);
ES7242_WriteReg(ES8388_ADDR, 0x2A, 0xB8); //RIGHT DAC TO RIGHT MIXER
ES7242_WriteReg(ES8388_ADDR, 0x04, 0x30); //Enable DAC and Enable Lout/Rout
ES7242_WriteReg(ES8388_ADDR, 0x2e, 0X10); //LOUT/ROUT volume
ES7242_WriteReg(ES8388_ADDR, 0x2f, 0X10);
ets_delay_us(50000);
ES7242_WriteReg(ES8388_ADDR, 0x2e, 0x1A); //LOUT/ROUT volume
ES7242_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
ES7242_WriteReg(ES8388_ADDR, 0x04, 0xc0); //Disable DAC and Lout/Rout
}
void ES8388_DAC_Play1(void)
{
int Vol = 0x1f;
ES7242_WriteReg(ES8388_ADDR, 0x02, 0xAA); //START DAC DLL and State Machine
ES7242_WriteReg(ES8388_ADDR, 0x2d, 0X00); //vroi=0 DelayT0(10); //Delay 10mS
ES7242_WriteReg(ES8388_ADDR, 0x04, 0x3C); //Enable DAC and Enable Lout/Rout
ets_delay_us(10000);
ES7242_WriteReg(ES8388_ADDR, 0x2e, Vol); //LOUT2/ROUT2
ES7242_WriteReg(ES8388_ADDR, 0x2f, Vol);
ES7242_WriteReg(ES8388_ADDR, 0x30, Vol); //LOUT1/ROUT1
ES7242_WriteReg(ES8388_ADDR, 0x31, Vol);
ES7242_WriteReg(ES8388_ADDR, 0x19, 0xF2); //DAC un-Mute
ES7242_WriteReg(ES8388_ADDR, 0x01, 0x40); //LPVrefBuf=0,Pdn_ana=0
ES7242_WriteReg(ES8388_ADDR, 0x00, 0x07); //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
}
void ES7242_Poweron_Init(void)
{
ets_printf("Writing Data to Registers\n");
#if 0
ES7242_WriteReg(ES7242_Address1, 0x00, 0x01);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address1, 0x01, 0x00);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address2, 0x00, 0x01);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address2, 0x01, 0x00);
ets_delay_us(10000);
#endif
#if 1
ES7242_WriteReg(ES7242_Address3, 0x00, 0x01);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address3, 0x01, 0x00);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address4, 0x00, 0x01);
ets_delay_us(10000);
ES7242_WriteReg(ES7242_Address4, 0x01, 0x00);
ets_delay_us(10000);
#endif
}
void ES7242_ADC_Record()
{
#if 0
ES7242_WriteReg(ES7242_Address1, 0x01, 0x0F);
ES7242_WriteReg(ES7242_Address1, 0x07, 0x00);
ES7242_WriteReg(ES7242_Address1, 0x08, 0x11);
ES7242_WriteReg(ES7242_Address1, 0x09, 0x00);
ES7242_WriteReg(ES7242_Address2, 0x01, 0x8F);
ES7242_WriteReg(ES7242_Address2, 0x07, 0x00);
ES7242_WriteReg(ES7242_Address2, 0x08, 0x11);
ES7242_WriteReg(ES7242_Address2, 0x09, 0x00);
#endif
#if 1
ES7242_WriteReg(ES7242_Address3, 0x01, 0x0F);
ES7242_WriteReg(ES7242_Address3, 0x07, 0x00);
ES7242_WriteReg(ES7242_Address3, 0x08, 0x11);
ES7242_WriteReg(ES7242_Address3, 0x09, 0x00);
#endif
#if 1
ES7242_WriteReg(ES7242_Address4, 0x01, 0x8F);
ES7242_WriteReg(ES7242_Address4, 0x07, 0x00);
ES7242_WriteReg(ES7242_Address4, 0x08, 0x11);
ES7242_WriteReg(ES7242_Address4, 0x09, 0x00);
#endif
}
void ES7242_ADC_StandBy()
{
}
void ES7242_init(void)
{
//I2C_MasterInit(0x0);
i2c_master_gpio_init();
ES8388_PowerOn_Init1();
ES8388_DAC_Play1();
//ES7242_Poweron_Init();
// ES7242_ADC_Record();
}
static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
{
if (iter == 0) {
iter = 1;
}
while (iter--) {
i2c_master_writeByte(data);
if (i2c_master_getAck()) {
i2c_master_stop();
i2c_master_wait(500); // Wait 500us and retry.
i2c_master_start();
} else {
return true;
}
}
i2c_master_stop();
return false;
}
#if 1
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
{
i2c_master_start();
if (false == I2C_Write_Byte(slave_add, 10)) {
ets_printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(reg_add, 10)) {
ets_printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(data, 10)) {
ets_printf("Slave is busy, TIME OUT");
}
i2c_master_stop();
}
#endif
#if 0
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
{
i2c_send_data_test(0x0, slave_add, reg_add, data);
//ets_delay_us(10000);
}
#endif
uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
{
i2c_master_start();
if (false == I2C_Write_Byte(slave_add, 0)) {
printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(reg_add, 0)) {
printf("Slave is busy, TIME OUT");
}
i2c_master_start();
i2c_master_writeByte(0x21);
uint8_t ack = i2c_master_getAck();
uint8_t Reve = i2c_master_readByte();
i2c_master_setAck(1);
i2c_master_stop();
return Reve;
}

View file

@ -0,0 +1,273 @@
#include "i2c_soft.h"
#include "rom/ets_sys.h"
#include "freertos/xtensa_api.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <stdio.h>
#include "ES8388.h"
#define ES8388_ADDR 0x22 // 0x22:CE=1;0x20:CE=0
static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
void ES8388_Init(uint32_t mode, uint32_t channel, uint32_t bits, uint32_t rate)
{
}
void ES8388_Start()
{
}
void ES8388_Stop()
{
}
void ES8388_Pause()
{
}
void ES8388_Resume()
{
}
void ES8388_SetVolume()
{
}
void ES8388_SetDacChannel(int32_t channel, int32_t value)
{
}
void ES8388_SetMute(int32_t channel)
{
}
void ES8388_SetMicGain()
{
}
void ES8388_PowerOn_Init(void)
{
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE -
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07); //PLAY BACK,ENREFR=0 //changed
ES8388_WriteReg(ES8388_ADDR, 0x2d, 0x00); //vroi=0
vTaskDelay(1);
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=1,ibiasgen_pdn=0,lpvrefbuf=1
vTaskDelay(1);
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3); //Reset STM and DLL
ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF); //Reset STM and DLL
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power up L/R DAC,Enable LO1/RO1,LO2/RO2,OUT3/MONO
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //LIN1/RIN1 as ADC Input
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT,LADC=Left data,RADC=right data W
ES8388_WriteReg(ES8388_ADDR, 0x0d, 0x02); //SINGLE SPEED,RATIO=256
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC Left Volume=0db
ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00); //ADC Right Volume=0db
ES8388_WriteReg(ES8388_ADDR, 0x17, 0x18); //I2S-16BIT
ES8388_WriteReg(ES8388_ADDR, 0x18, 0x02); //SINGLE SPEED,RATIO=256
ES8388_WriteReg(ES8388_ADDR, 0x19, 0x36); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
ES8388_WriteReg(ES8388_ADDR, 0x1A, 0x00); //LDAC volume=0db,RDAC Volume=0db
ES8388_WriteReg(ES8388_ADDR, 0x1B, 0x00);
ES8388_WriteReg(ES8388_ADDR, 0x19, 0x32); //SOFT RAMP RATE=32LRCKS/STEP,Enable ZERO-CROSS CHECK,DAC MUTE
ES8388_WriteReg(ES8388_ADDR, 0x27, 0xB8); //Left DAC TO Left MIXER
ES8388_WriteReg(ES8388_ADDR, 0x28, 0x38);
ES8388_WriteReg(ES8388_ADDR, 0x29, 0x38);
ES8388_WriteReg(ES8388_ADDR, 0x2A, 0xB8); //RIGHT DAC TO RIGHT MIXER
ES8388_WriteReg(ES8388_ADDR, 0x04, 0x30); //Enable DAC and Enable Lout/Rout
ES8388_WriteReg(ES8388_ADDR, 0x2e, 0X10); //LOUT/ROUT volume
ES8388_WriteReg(ES8388_ADDR, 0x2f, 0X10);
vTaskDelay(5);
ES8388_WriteReg(ES8388_ADDR, 0x2e, 0x1A); //LOUT/ROUT volume
ES8388_WriteReg(ES8388_ADDR, 0x2f, 0x1A);
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xc0); //Disable DAC and Lout/Rout
}
void ES8388_DAC_Play()
{
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00); //START DAC DLL and State Machine
ES8388_WriteReg(ES8388_ADDR, 0x2d, 0X00); //vroi=0 DelayT0(10); //Delay 10mS
ES8388_WriteReg(ES8388_ADDR, 0x04, 0x3C); //Enable DAC and Enable Lout/Rout
vTaskDelay(1);
ES8388_WriteReg(ES8388_ADDR, 0x2e, Vol); //LOUT2/ROUT2
ES8388_WriteReg(ES8388_ADDR, 0x2f, Vol);
ES8388_WriteReg(ES8388_ADDR, 0x30, Vol); //LOUT1/ROUT1
ES8388_WriteReg(ES8388_ADDR, 0x31, Vol);
ES8388_WriteReg(ES8388_ADDR, 0x19, 0xF2); //DAC un-Mute
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //LPVrefBuf=0,Pdn_ana=0
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x07); //Enfr=0,Play&Record Mode,(0x17-both of mic&paly)
}
void ES8388_ALC()
{
ES8388_WriteReg(ES8388_ADDR, 0x12, 0xf2); //ALC for Microphone
ES8388_WriteReg(ES8388_ADDR, 0x13, 0xb0);
ES8388_WriteReg(ES8388_ADDR, 0x14, 0x05);
ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
ES8388_WriteReg(ES8388_ADDR, 0x16, 0x7b);
}
void ES8388_ADC_Record()
{
/*
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //Codec in I2S slave mode
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC Power-up
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //DAC Power-DN,LOUT/ROUT disable
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //DAC Power-DN,LOUT/ROUT disable
ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //ADC Power-up
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
ES8388_WriteReg(ES8388_ADDR, 0x09, 0x77); //Analog In PGA=24db
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //MIC INPUT FROM LIN1/RIN1
// ES8388_WriteReg(0x0A,0x50); //MIC INPUT FROM LIN2/RIN2
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //I2S-16BIT, leftADC-Left Channel, RightADC-Right Channel
ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //MCLK/LRCK=256
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0dB
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x55);
vTaskDelay(1); //Delay 10mS
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式且EnRefr=1
ES8388_ALC();
ES8388_ADC_StandBy();
*/
//unsigned int i;
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x36); //Power down whole chip analog
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x72); //power up whole chip analog
//ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //stop STM and DLL, power down DAC&ADC vref
//ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF0); //power up DAC&ADC vref
ES8388_WriteReg(ES8388_ADDR, 0x2B, 0x80); //set internal ADC and DAC use the same LRCK clock, ADC LRCK as internal LRCK
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xF3); //ADC clock is same as DAC. Use ADC MCLK as internal MCLK
ES8388_WriteReg(ES8388_ADDR, 0x08, 0x00); //CODEC IN I2S SLAVE MODE-0x00;master-0x80
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //power down DAC, Disable LOUT&ROUT
ES8388_WriteReg(ES8388_ADDR, 0x05, 0x00); //low power setting
ES8388_WriteReg(ES8388_ADDR, 0x06, 0xC3);
ES8388_WriteReg(ES8388_ADDR, 0x0A, 0x00); //select LIN1&RIN1 as Microphone
ES8388_WriteReg(ES8388_ADDR, 0x0B, 0x00);
// ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x6F); //ADC 16BIT PCM & right=left
ES8388_WriteReg(ES8388_ADDR, 0x0C, 0x0C); //ADC I2S-16BIT
ES8388_WriteReg(ES8388_ADDR, 0x0D, 0x02); //ADCLRCK = MCLK/256
ES8388_WriteReg(ES8388_ADDR, 0x10, 0x00); //ADC VOLUME = 0DB
ES8388_WriteReg(ES8388_ADDR, 0x11, 0x00);
ES8388_WriteReg(ES8388_ADDR, 0x09, 0x88); //MIC PGA =24DB
ES8388_WriteReg(ES8388_ADDR, 0x12, 0xE2); //MIC ALC SETTING
ES8388_WriteReg(ES8388_ADDR, 0x13, 0xC0);
ES8388_WriteReg(ES8388_ADDR, 0x14, 0x12);
ES8388_WriteReg(ES8388_ADDR, 0x15, 0x06);
ES8388_WriteReg(ES8388_ADDR, 0x16, 0xC3);
ES8388_WriteReg(ES8388_ADDR, 0x02, 0x00); //startup FSM and DLL
ES8388_WriteReg(ES8388_ADDR, 0x03, 0x00); //Power up ADC, Enable LIN&RIN, Power down MICBIAS, set int1lp to low power mode
vTaskDelay(1);
//ES8388_WriteReg(ES8388_ADDR, 0x01, 0x40); //pdn_ana=0,ibiasgen_pdn=0
//ES8388_WriteReg(ES8388_ADDR, 0x00, 0x05); //置ES8350于PLAYBACK & RECORD 模式且EnRefr=1
}
void ES8388_ADC_StandBy()
{
ES8388_WriteReg(ES8388_ADDR, 0x00, 0x01); //置ES8350于PLAYBACK & RECORD 模式且EnRefr=1
ES8388_WriteReg(ES8388_ADDR, 0x01, 0x58); //pdn_ana=0,ibiasgen_pdn=0
vTaskDelay(1); //Delay 10mS
ES8388_WriteReg(ES8388_ADDR, 0x03, 0xFF); //ADC Power-Down
ES8388_WriteReg(ES8388_ADDR, 0x04, 0xC0); //DAC Power-DN,LOUT/ROUT disable
ES8388_WriteReg(ES8388_ADDR, 0x02, 0xf3); //关闭录音
}
void ES8388_init(void)
{
i2c_master_gpio_init();
ES8388_PowerOn_Init();
// ES8388_ADC_Record();
//ES8388_DAC_Play();
}
static bool I2C_Write_Byte(uint8_t data, uint8_t iter)
{
if (iter == 0) {
iter = 1;
}
while (iter--) {
i2c_master_writeByte(data);
if (i2c_master_getAck()) {
i2c_master_stop();
ets_delay_us(500); // Wait 500us and retry.
i2c_master_start();
} else {
return true;
}
}
i2c_master_stop();
return false;
}
void ES8388_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data)
{
i2c_master_start();
if (false == I2C_Write_Byte(slave_add, 30)) {
printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(reg_add, 30)) {
printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(data, 30)) {
printf("Slave is busy, TIME OUT");
}
i2c_master_stop();
}
uint8_t ES8388_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat)
{
i2c_master_start();
if (false == I2C_Write_Byte(slave_add, 10)) {
printf("Slave is busy, TIME OUT");
}
if (false == I2C_Write_Byte(reg_add, 10)) {
printf("Slave is busy, TIME OUT");
}
i2c_master_start();
i2c_master_writeByte(0x21);
uint8_t ack = i2c_master_getAck();
uint8_t Reve = i2c_master_readByte();
i2c_master_setAck(1);
i2c_master_stop();
return Reve;
}

View file

@ -0,0 +1,388 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP8266 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#include "MediaHal.h"
#include "audio_log.h"
#include "driver/gpio.h"
#include "esp_types.h"
//#include "inc/Vs10xx.h"
#include "AP80/Ap80xx.h"
#include "EspAudioCom.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "MyString.h"
#include "ES8388.h"
// 2---ES8388
// 1---AP8048
// 0---VS1053
#define PA_POINT_PWR 25 // GPIO25
#define AP_POINT_PWR 26 // GPIO26
#define CODECTYPE 1
static char* LOGPRE = "[mediaHal Err]";
static char* LOGPRD = "[mediaHal Info]";
static MediaState mediaStatus = 0;
static uint32_t mediaVol = 50;
void mediaHalInit(void)
{
#if CODECTYPE==0
VS_Init();
VS_Sine_Test();
VS_HD_Reset();
VS_Soft_Reset();
VS_Set_All();
#elif CODECTYPE==1
// AP8048 PWRKEY
gpio_config_t io_conf;
memset(&io_conf, 0, sizeof(io_conf));
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO26_U, FUNC_GPIO26_GPIO26);
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO26_U, FUN_PU);
io_conf.pin_bit_mask = GPIO_SEL_26;
io_conf.mode = GPIO_MODE_OUTPUT;
io_conf.intr_type = GPIO_PIN_INTR_DISABLE ;
gpio_config(&io_conf);
gpio_set_level(AP_POINT_PWR, 0x01); // Enable the AP80 powerkey
// PA PWR
PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO25_U, FUNC_GPIO25_GPIO25);
SET_PERI_REG_MASK(PERIPHS_IO_MUX_GPIO25_U, FUN_PU);
gpio_set_level(PA_POINT_PWR, 0x01);
apInit();
#elif CODECTYPE==2
ES8388_init();
#endif
mediaStatus = MediaState_Initialized;
LOGI("mediaHalInit ok");
}
MediaErr mediaHalDataRead(uint8_t *dat, int *len)
{
if ((NULL == dat)
/*|| (MediaState_Playing != mediaStatus)*/) {
printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
return MediaErr_ParaError;
}
uint32_t ret = 0;
#if CODECTYPE==0
ret = VS_Send_MusicData(dat);
#elif CODECTYPE==1
ret = apMicReadData(dat, (uint16_t*)len);
#endif
if (ret != MediaErr_NoError) {
printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
return MediaErr_CodecError;
} else {
return MediaErr_NoError;
}
}
MediaErr mediaHalDataWrite(uint8_t *dat, int len)
{
if ((NULL == dat)
|| (MediaState_Playing != mediaStatus)) {
printf("%s,[func]%s,MediaState is not playing[%x]\r\n", LOGPRE, __func__, mediaStatus);
return MediaErr_ParaError;
}
uint32_t ret = 0;
#if CODECTYPE==0
ret = VS_Send_MusicData(dat);
#elif CODECTYPE==1
ret = apSendData(dat, len);
#endif
if (ret != MediaErr_NoError) {
printf("%s,[func]%s,Send data to codec failed,ret=%d\r\n", LOGPRE, __func__, ret);
return MediaErr_CodecError;
} else {
return MediaErr_NoError;
}
}
void mediaHalReset(void)
{
// VS_HD_Reset();
//VS_Soft_Reset();
}
MediaErr mediaHalPlay(EspAudioMeidaType type)
{
uint32_t ret = 0;
#if CODECTYPE==0
VS_Restart_Play(); //
VS_Reset_DecodeTime(); //
VS_SPI_SpeedHigh();
#else
if ((MediaState_Initialized == mediaStatus)
|| (MediaState_Stoped == mediaStatus)) {
if (EspAudioMeidaType_Aac == type) {
ret = apPlayStart("radio", sizeof("radio"), AAC_DECODER);
} else if (EspAudioMeidaType_Mp3 == type) {
ret = apPlayStart("radio", sizeof("radio"), MP3_DECODER);
} else if (EspAudioMeidaType_Wav == type) {
ret = apPlayStart("radio", sizeof("radio"), WAV_DECODER);
} else if (EspAudioMeidaType_Flac == type) {
ret = apPlayStart("radio", sizeof("radio"), FLAC_DECODER);
} else if (EspAudioMeidaType_Opus == type) {
ret = apPlayStart("radio", sizeof("radio"), OPUS_DECODER);
} else if (EspAudioMeidaType_Pcm == type) {
ret = apPlayStart("radio", sizeof("radio"), PCM_DECODER);
}
else {
printf("%s,[func]%s,Music type[%d] does not support\r\n", LOGPRE, __func__, type);
}
} else {
apPlayResume();
}
printf("%s,[func]%s, mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
#endif
mediaStatus = MediaState_Playing;
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalPause(void)
{
uint32_t ret = 0;
if (MediaState_Playing == mediaStatus) {
apPlayPause();
mediaStatus = MediaState_Paused;
}
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
printf("%s,[func]%s,mediaStatus=%d\r\n", LOGPRD, __func__, mediaStatus);
return ret;
}
MediaErr mediaHalStop(void)
{
uint32_t ret = 0;
#if CODECTYPE==0
VS_Cancel();
#elif CODECTYPE==1
apPlayStop();
#endif
mediaStatus = MediaState_Stoped;
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalVolumeSet(uint8_t value)
{
uint32_t ret = 0;
uint32_t tmp = value;
LOGD("volmue=%d", tmp);
#if CODECTYPE==0
vsset.mvol = value;
mediaVol = vsset.mvol;
tmp = (value * 200) / 100 + 50;
mediaVol = tmp;
VS_Set_Vol(tmp); // when vs1053 does not init,this call will be hang.
#elif CODECTYPE==1
ret = apVolSet(tmp);
#endif
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalMute(void)
{
uint32_t ret = 0;
#if CODECTYPE==0
VS_Set_Vol(0);
#elif CODECTYPE==1
ret = apVolMuteEnable();
#endif
mediaVol = 0;
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalStatusGet(MediaState *staus)
{
if (NULL == staus) {
return MediaErr_ParaError;
}
*staus = mediaStatus;
return MediaErr_NoError;
}
void mediaHalSleep(void)
{
// GPIO_OUTPUT_SET(PA_POINT_PWR, 0);
// GPIO_OUTPUT_SET(AP_POINT_PWR, 0);
printf("%s mediaHal sleep\r\n", LOGPRE);
}
void mediaHalWakeup(void)
{
// GPIO_OUTPUT_SET(PA_POINT_PWR, 1);
// GPIO_OUTPUT_SET(AP_POINT_PWR, 1);
printf("%s Codec wakeup\r\n", LOGPRE);
}
MediaErr mediaHalDecodeTimeRest()
{
uint32_t ret = apRestDecodeTime();
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalDecodeTimeGet(uint32_t *time)
{
if (NULL == time) {
return MediaErr_ParaError;
}
uint32_t ret = apGetDecodeTime((DecodeTime*)time);
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalMusicInfoGet(MusicInfo *info)
{
if (NULL == info) {
return MediaErr_ParaError;
}
uint32_t ret = apGetInfo((SongInformation*)info);
if (ret != OK_RESPONSE) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
ret = MediaErr_CodecError;
}
return ret;
}
MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info)
{
MediaErr err = MediaErr_NoError;
uint8_t ret = OK_RESPONSE;
switch (mode) {
case MediaMode_Encode:
{
setEnccodeInfo tmpInfo;
memset(&tmpInfo, 0, sizeof(tmpInfo));
ret = apSetEncodeMode();
tmpInfo.streamDirection = 1;
tmpInfo.numChannels = info->num_channels;
tmpInfo.sampleRate = info->sampling_rate;
tmpInfo.encoderType = info->stream_type; //OPUS_ENCODER;
ret = apEncodeStart();
ret += apSetEncodeInfo(&tmpInfo);
LOGD("apSetEncodeInfo ret = %d %d\n", ret, tmpInfo.encoderType,
tmpInfo.sampleRate, tmpInfo.numChannels);
break;
}
case MediaMode_Decode:
{
setDecodeInfo tmpInfo;
memset(&tmpInfo, 0, sizeof(tmpInfo));
ret = apSetDecodeMode();
tmpInfo.streamDirection = 0;
tmpInfo.numChannels = info->num_channels;
tmpInfo.sampleRate = info->sampling_rate;
ret += apSetDecodeInfo(&tmpInfo);
LOGD("apSetDecodeInfo ret=%d\n", ret);
break;
}
case MediaMode_AuxIn:
ret = apSetDecodeMode();
break;
default:
err = MediaErr_NotSuport;
break;
}
if ((ret != OK_RESPONSE) && (ERROR_OTHER!= ret)) {
printf("%s,[func]%s,ret=%d\r\n", LOGPRE, __func__, ret);
err = MediaErr_CodecError;
}
return err;
}
EspAudioMeidaType checkMediaType(const char* targetUri)
{
EspAudioMeidaType type;
if (EndsWith(targetUri, ".wav", 1) != 0) {
type = EspAudioMeidaType_Wav;
} else if (EndsWith(targetUri, ".aac", 1) != 0) {
type = EspAudioMeidaType_Aac;
} else if (EndsWith(targetUri, ".mp3", 1) != 0) {
type = EspAudioMeidaType_Mp3;
} else if (EndsWith(targetUri, ".amr", 1) != 0) {
type = EspAudioMeidaType_Amr;
} else if (EndsWith(targetUri, ".alac", 1) != 0) {
type = EspAudioMeidaType_Alac;
} else if (EndsWith(targetUri, ".flac", 1) != 0) {
type = EspAudioMeidaType_Flac;
} else if (EndsWith(targetUri, ".ape", 1) != 0) {
type = EspAudioMeidaType_Ape;
} else if (EndsWith(targetUri, ".m3u8", 1) != 0) {
type = EspAudioMeidaType_M3u;
} else if (EndsWith(targetUri, ".opu", 1) != 0) {
type = EspAudioMeidaType_Opus;
} else if (EndsWith(targetUri, ".pcm", 1) != 0) {
type = EspAudioMeidaType_Pcm;
} else {
type = EspAudioMeidaType_Unknown;
}
return type;
}
// end

View file

@ -0,0 +1,15 @@
#
# Component Makefile
#
# This Makefile should, at the very least, just include $(SDK_PATH)/Makefile. By default,
# this will take the sources in the src/ directory, compile them and link them into
# lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable,
# please read the SDK documents if you need to do this.
#
COMPONENT_ADD_INCLUDEDIRS := include include/AP80 include/ES8388 include/driver \
../misc/include
COMPONENT_SRCDIRS := AP80 ES8388 Driver test .
include $(IDF_PATH)/make/component_common.mk

View file

@ -0,0 +1,253 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2015 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __AP80XX_H__
#define __AP80XX_H__
#include <stdint.h>
#pragma pack (1)
#define CHIPTYPE 32
#if CHIPTYPE == 32
#include "soc/gpio_sig_map.h"
#define SPIMasterSendData spi_master_send_data
#define HSPICLK_OUT_MUX_IDX HSPICLK_OUT_IDX
#define SpiNum_HSPI SPI_NUM_SPI2
#define AP80XXENABLEDMA 1
#define AP80XXENABLEINT 1
#define CALLPLAYOBJ_EN 1
#define SPIM_STREAM_CONTROL_GET_STATUS() (gpio_get_level(GPIO_NUM_22))
#elif CHIPTYPE == 31
#define SPIM_STREAM_CONTROL_GET_STATUS() (GPIO_INPUT_GET(22))
#endif
#define EAU_SYNC_BYTE 'S'
#define EAU_COMMAND_LENGTH (1)
#define EAU_SYNC_WORD_LENGTH (1)
#define EAU_CRC_VALUE_LENGTH (2)
#define EAU_RESEND_IF_CRC_ERROR (1)
#define EAU_SEND_DATA_LENGTH (32 * 48)
#define EAU_SEND_FARMA_LENGTH (32)
#define EAU_RECV_FARMA_LENGTH (32)
#define OK_RESPONSE (0x00)
//Òì³£¶¨Òå
#define ERROR_TIME_OUT (0x01)
#define ERROR_STREAM_FULL (0x02)
#define ERROR_CRC (0x03)
#define ERROR_RESPONSE (0x04)
#define ERROR_CMD (0x05)
#define ERROR_PARAMETER (0x06)
#define ERROR_INIT (0x07)
#define ERROR_OTHER (0x08)
#define ERROR_PROMODE (0x09)
#define ERROR_DEVICE_TIME_OUT (0x0A)
#define ERROR_START (0x0B)
#define ERROR_DMABUSY (0x0C)
#define SPIDATABUFMAXLEN (64)
typedef uint32_t DecodeTime;
typedef enum _SSPP_CMD
{
EAU_CMD_UNKOWN = 0,
EAU_CMD_START,
EAU_CMD_PAUSE,
EAU_CMD_RESUME,
EAU_CMD_STOP,
EAU_CMD_MUTE,
EAU_CMD_UNMUTE,
EAU_CMD_DATA,
EAU_CMD_WRITE_DATA = EAU_CMD_DATA,
EAU_CMD_VOL_SET,
EAU_CMD_VOL_ADD,
EAU_CMD_VOL_SUB,
EAU_CMD_INFO_GET,
EAU_CMD_INFO_SET,
EAU_CMD_TIME_REST,
EAU_CMD_TIME_GET,
EAU_CMD_VERSION_GET,
EAU_CMD_ENCODE_MODE,
EAU_CMD_DECODE_MODE,
EAU_CMD_READ_DATA,
EAU_CMD_LIN_SWITCH,
EAU_CMD_MIC_SWITCH,
EAU_CMD_ENCODE_START,
}SSPP_CMD;
typedef struct _MASTERCmdContext
{
uint8_t SyncWord;
uint8_t Command;
uint16_t Content;
uint16_t CrcValue;
}MASTERCmdContext,EAUCmdContext;
typedef struct _EAUCmdResponseContext
{
uint8_t SyncWord;
uint8_t Command;
uint16_t Response;
uint16_t CrcValue;
}EAUCmdResponseContext;
typedef struct _DataContext
{
uint8_t SyncWord;
uint8_t data[EAU_SEND_DATA_LENGTH+EAU_CRC_VALUE_LENGTH];
}EAUDataContext;
typedef enum __EAU_CMD_RESPONSE
{
EAU_CMD_RESP_UNKOWN = 0,
EAU_CMD_RESP_OKCMD,
EAU_CMD_RESP_ERCMD,
EAU_CMD_RESP_OKSEND,
EAU_CMD_RESP_RESEND,
EAU_CMD_RESP_NEXTSEND,
EAU_CMD_RESP_INITERROR,
EAU_CMD_RESP_STATEERROR,
}EAU_CMD_RESPONSE;
/**
* @ly Audio encoder type Ex
*/
typedef enum _EncoderTypeEx
{
OPUS_ENCODER_EX = 1, /**< OPUS encoder */
PCM_ENCODER_EX, /**< PCM encoder */
} EncoderTypeEx;
/**
* @ly Audio Decoder Type Set
*/
typedef enum _DecoderType
{
UNKOWN_DECODER = 0, /**< Unknown decoder */
PURE_SOFTWARE_DECODERS = 1, /**< Pure software decoders as follows */
WAV_DECODER, /**< WAV decoder */
FLAC_DECODER, /**< FLAC decoder */
AAC_DECODER, /**< AAC decoder */
AIF_DECODER, /**< AIFF and AIFC decoder */
ALAC_DECODER, /**< ALAC and AIFC decoder */
OPUS_DECODER, /**< OPUS decoder */
PCM_DECODER, /**< PCM decoder */
WITH_HARDWARE_DECODERS = 128, /**< Decoders with hardware as follows */
MP3_DECODER, /**< MP3 decoder */
WMA_DECODER, /**< WAM decoder */
SBC_DECODER, /**< SBC decoder */
} DecoderType;
/**
* @ly Song Information
*/
typedef struct _SongInformation
{
int32_t stream_type; /**< Stream type, must be in @code StreamTypeSet */
uint32_t num_channels; /**< Number of channels */
uint32_t sampling_rate; /**< Sampling rate, unit: Hz */
uint32_t bitrate; /**< Bit rate, unit:bps */
uint32_t duration; /**< Total play time, unit:ms */
uint32_t file_size; /**< Song file size in bytes . */
uint16_t firmware_ver; /**< AP80xx firmware version . */
uint16_t firmware_num; /**< AP80xx firmware number . */
uint8_t Stream_buf_is_Empty; /**< Stream_buf_is_Empty . */
uint8_t RFU; /**< RFU . */
} SongInformation;
/**
* @ly code Information
*/
typedef struct _setdeccodeInfo
{
int32_t streamDirection; /**< Stream direction */
uint32_t numChannels; /**< Number of channels */
uint32_t sampleRate; /**< Bit rate, unit:bps */
uint32_t decoderType; /**< Decoder Type:OPUS,PCM */
uint32_t frameSize; /**< opus and pcm */
uint32_t RFU2; /**< RFU */
uint32_t RFU3; /**< RFU */
uint32_t RFU4; /**< RFU */
uint32_t RFU5; /**< RFU */
uint32_t RFU6; /**< RFU */
uint32_t RFU7; /**< RFU */
} setDecodeInfo;
/**
* @ly encode Information
*/
typedef struct _set_enccode_info
{
int32_t streamDirection; /**< Stream direction */
uint32_t numChannels; /**< Number of channels */
uint32_t sampleRate; /**< Sample rate, unit:bps */
uint32_t encoderType; /**< Encoder Type:OPUS,PCM */
uint32_t frameSize; /**< RFU */
uint32_t RFU2; /**< RFU */
uint32_t RFU3; /**< RFU */
uint32_t RFU4; /**< RFU */
uint32_t RFU5; /**< RFU */
uint32_t RFU6; /**< RFU */
uint32_t RFU7; /**< RFU */
}setEnccodeInfo;
//public function
void apInit();
uint8_t apPlayStop(void);
uint8_t apPlayPause(void);
uint8_t apLinSwitch(void);
uint8_t apMicSwitch(void);
uint8_t apPlayResume(void);
uint8_t apEncodeStart(void);
uint8_t apVolSet(uint16_t vol);
uint8_t apSetEncodeMode(void);
uint8_t apSetDecodeMode(void);
uint8_t apVolMuteEnable(void);
uint8_t apVolMuteDisable(void);
uint8_t apRestDecodeTime(void);
uint8_t apSetWaitTime(uint32_t waitTime);
uint8_t apGetDecodeTime(DecodeTime *time);
uint8_t apGetInfo(SongInformation *songInfo);
uint8_t apSetDecodeInfo(setDecodeInfo *decodeInfo);
uint8_t apSetEncodeInfo(setEnccodeInfo *encodeInfo);
uint8_t apSendData(uint8_t *sendData, uint16_t sendLen);
uint8_t apMicReadData(uint8_t *readData, uint16_t *readLen);
uint8_t apPlayStart(const char *songFileName, uint8_t len, DecoderType decType);
//private function
void audio_test_main();
void mic_test();
void audio_test_main();
void apSetResponse(bool responseEnable);
void printfByteS(uint8_t *indata, uint16_t len);
#endif // __AP80XX_H__

View file

@ -0,0 +1,28 @@
/**
**************************************************************************************
* @file crc.h
* @brief Calculate CRC Value
*
* @author Aissen Li
* @version V1.0.0
*
* &copy; Shanghai Mountain View Silicon Technology Co.,Ltd. All rights reserved.
**************************************************************************************
*/
#ifndef __CRC_H__
#define __CRC_H__
#ifdef __cplusplus
extern "C" {
#endif//__cplusplus
#include <stdint.h>
uint16_t GetCRC16NBS(uint8_t* data, uint32_t length);
#ifdef __cplusplus
}
#endif//__cplusplus
#endif//__CRC_H__

View file

@ -0,0 +1,27 @@
#ifndef __ES8388_H
#define __ES8388_H
#include "esp_types.h"
#include "rom/ets_sys.h"
#define ES7154_Address 0x00
#define ES7242_Address1 0x20
#define ES7242_Address2 0x22
#define ES7242_Address3 0x24
#define ES7242_Address4 0x26
void ES7242_init(void);
void ES7242_Poweron_Init(void);
//void ES8388_DAC_Play(void);
//void ES8388_ALC(void);
void ES7242_ADC_Record(void);
void ES7242_ADC_StandBy(void);
static bool I2C_Write_Byte(uint8_t data, uint8_t iter);
void ES7242_WriteReg(uint8_t slave_add, uint8_t reg_add, uint8_t data);
uint8_t ES7242_ReadReg(uint8_t slave_add, uint8_t reg_add, uint8_t dat);
void I2C_MasterInit(uint8_t init_num);
void i2c_master_read_test();
#endif

View file

@ -0,0 +1,78 @@
#ifndef __ES8388_H
#define __ES8388_H
#include "esp_types.h"
#define ES8388_CONTROL1 0x00
#define ES8388_CONTROL2 0x01
#define ES8388_CHIPPOWER 0x02
#define ES8388_ADCPOWER 0x03
#define ES8388_DACPOWER 0x04
#define ES8388_CHIPLOPOW1 0x05
#define ES8388_CHIPLOPOW2 0x06
#define ES8388_ANAVOLMANAG 0x07
#define ES8388_MASTERMODE 0x08
#define ES8388_ADCCONTROL1 0x09
#define ES8388_ADCCONTROL2 0x0a
#define ES8388_ADCCONTROL3 0x0b
#define ES8388_ADCCONTROL4 0x0c
#define ES8388_ADCCONTROL5 0x0d
#define ES8388_ADCCONTROL6 0x0e
#define ES8388_ADCCONTROL7 0x0f
#define ES8388_ADCCONTROL8 0x10
#define ES8388_ADCCONTROL9 0x11
#define ES8388_ADCCONTROL10 0x12
#define ES8388_ADCCONTROL11 0x13
#define ES8388_ADCCONTROL12 0x14
#define ES8388_ADCCONTROL13 0x15
#define ES8388_ADCCONTROL14 0x16
#define ES8388_DACCONTROL1 0x17
#define ES8388_DACCONTROL2 0x18
#define ES8388_DACCONTROL3 0x19
#define ES8388_DACCONTROL4 0x1a
#define ES8388_DACCONTROL5 0x1b
#define ES8388_DACCONTROL6 0x1c
#define ES8388_DACCONTROL7 0x1d
#define ES8388_DACCONTROL8 0x1e
#define ES8388_DACCONTROL9 0x1f
#define ES8388_DACCONTROL10 0x20
#define ES8388_DACCONTROL11 0x21
#define ES8388_DACCONTROL12 0x22
#define ES8388_DACCONTROL13 0x23
#define ES8388_DACCONTROL14 0x24
#define ES8388_DACCONTROL15 0x25
#define ES8388_DACCONTROL16 0x26
#define ES8388_DACCONTROL17 0x27
#define ES8388_DACCONTROL18 0x28
#define ES8388_DACCONTROL19 0x29
#define ES8388_DACCONTROL20 0x2a
#define ES8388_DACCONTROL21 0x2b
#define ES8388_DACCONTROL22 0x2c
#define ES8388_DACCONTROL23 0x2d
#define ES8388_DACCONTROL24 0x2e
#define ES8388_DACCONTROL25 0x2f
#define ES8388_DACCONTROL26 0x30
#define ES8388_DACCONTROL27 0x31
#define ES8388_DACCONTROL28 0x32
#define ES8388_DACCONTROL29 0x33
#define ES8388_DACCONTROL30 0x34
#define Vol 0x0F
void ES8388_init(void);
void ES8388_PowerOn_Init(void);
void ES8388_DAC_Play(void);
void ES8388_ALC(void);
void ES8388_ADC_Record(void);
void ES8388_ADC_StandBy(void);
#endif

View file

@ -0,0 +1,130 @@
/*
* ESPRSSIF MIT License
*
* Copyright (c) 2016 <ESPRESSIF SYSTEMS (SHANGHAI) PTE LTD>
*
* Permission is hereby granted for use on ESPRESSIF SYSTEMS ESP32 only, in which case,
* it is free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the Software is furnished
* to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
#ifndef __MEDIAHAL_H__
#define __MEDIAHAL_H__
#include <stdint.h>
//*****************************************************************************
//
// Make sure all of the definitions in this header have a C binding.
//
//*****************************************************************************
#ifdef __cplusplus
extern "C"
{
#endif
#define AP_POINT_PWR 26 // GPIO26 AP8048
#define PA_POINT_PWR 25 // GPIO25
typedef enum {
MediaState_Initialized = 0, /* codec is initialized */
MediaState_Stoped, /* codec is stoped */
MediaState_Transit, /* codec is busy in a transition */
MediaState_Playing, /* codec is currently playing */
MediaState_Paused, /* codec is in the paused state for playback */
MediaState_Ended, /* codec finished decoding media, media has stopped without user request. */
MediaState_Error, /* codec was given a URI that could not be played */
MediaState_Unknow /* unknown playstate */
}MediaState;
typedef enum
{
EspAudioMeidaType_Unknown = 0,
EspAudioMeidaType_Wav,
EspAudioMeidaType_Aac,
EspAudioMeidaType_Mp3,
EspAudioMeidaType_Amr,
EspAudioMeidaType_Alac,
EspAudioMeidaType_Flac,
EspAudioMeidaType_Ape,
EspAudioMeidaType_M3u,
EspAudioMeidaType_Opus,
EspAudioMeidaType_Pcm,
EspAudioMeidaType_Max,
}EspAudioMeidaType;
typedef enum {
MediaErr_NoError = 0,
MediaErr_ParaError,
MediaErr_CodecInitFailed,
MediaErr_CodecError,
MediaErr_NotSuport,
} MediaErr;
typedef enum {
MediaMode_Decode = 0,
MediaMode_Encode = 1,
MediaMode_AuxIn = 2,
MediaMode_Max = 3,
} MediaMode;
typedef struct
{
int32_t stream_type; /**< Stream type, must be in @code StreamTypeSet */
uint32_t num_channels; /**< Number of channels */
uint32_t sampling_rate; /**< Sampling rate, unit: Hz */
uint32_t bitrate; /**< Bit rate, unit:bps */
uint32_t duration; /**< Total play time, unit:ms */
uint32_t file_size; /**< Song file size in bytes . */
uint16_t firmware_ver; /**< AP80xx firmware version . */
uint16_t firmware_num; /**< AP80xx firmware number . */
uint8_t bufEmpty; /**< Stream_buf_is_Empty . */
uint8_t RFU; /**< RFU . */
} MusicInfo;
void mediaHalInit();
MediaErr mediaHalDataWrite(uint8_t *dat, int len);
MediaErr mediaHalDataRead(uint8_t *dat, int *len);
MediaErr mediaHalPlay(EspAudioMeidaType type);
MediaErr mediaHalPause(void);
MediaErr mediaHalStop(void);
void mediaHalReset(void);
MediaErr mediaHalVolumeSet(uint8_t value);
MediaErr mediaHalMute(void);
MediaErr mediaHalStatusGet(MediaState *staus);
void mediaHalSleep(void);
void mediaHalWakeup(void);
MediaErr mediaHalModeSet(MediaMode mode, MusicInfo* info);
MediaErr mediaHalDecodeTimeRest(void);
MediaErr mediaHalDecodeTimeGet(uint32_t *time);
MediaErr mediaHalMusicInfoGet(MusicInfo *info);
EspAudioMeidaType checkMediaType(const char* targetUri);
#ifdef __cplusplus
}
#endif
#endif // __MEDIAHAL_H__

View file

@ -0,0 +1,127 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _DRIVER_DMA_H_
#define _DRIVER_DMA_H__
#include <esp_types.h>
#include "esp_err.h"
#ifdef __cplusplus
extern "C" {
#endif
/** \defgroup Driver_APIs Driver APIs
* @brief Driver APIs
*/
/** @addtogroup Driver_APIs
* @{
*/
/**
* @brief DMA queue description.
*/
typedef struct {
uint32_t block_size: 12;
uint32_t data_length: 12;
uint32_t unused: 5;
uint32_t sub_sof: 1;
uint32_t eof: 1;
uint32_t owner: 1;
uint32_t buf_ptr;
uint32_t next_link_ptr;
} dma_queue_t;
/**
* @brief DMA element description
*/
typedef struct {
uint32_t *buffer_addr;
dma_queue_t *first_queue;
dma_queue_t *last_queue;
dma_queue_t backup_queue;
} dma_element_t;
/**
* @brief DMA ping-pong buffer object description
*/
typedef struct {
dma_element_t *ping;
dma_element_t *pong;
uint32_t len;
uint32_t queue_cnt;
} ping_pong_buf_t;
/**
* @brief Create a ping-pong buffer object used by DMA.
*
* @param [in] bufLen
* Set the buffer length.
* --------------------
* | ping | Pong |
* --------------------
* | bufLen | bufLen |
* --------------------
*
* @return uint32*, NULL:indicates parameter error, others indicates ping-pong buffer address.
*/
ping_pong_buf_t* dma_buf_create(uint32_t bufLen);
/**
* @brief Reset the dma buffer length.
*
* @param [in] obj
* Pointer to a struct ping_pong_buf_t that indicates the object length to be reset to bufLen.
*
* @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK :indicates success.
*/
esp_err_t dma_buf_len_reset(ping_pong_buf_t *obj);
/**
* @brief Set the buffer length before the start.
*
* @param [in] obj
* Pointer to a struct spi_dma_attr_t.
* @param [in] len
* Set the transmit length .
*
* @return uint32*, ESP_FAIL:indicates parameter error, ESP_OK: indicates success.
*/
esp_err_t dma_buf_len_set(ping_pong_buf_t *obj, dma_element_t *element, uint32_t len);
/**
* @brief Destroy the ping-pong buffer instance.
*
* @param [in] obj
* Pointer to a struct ping_pong_buf_t that indicates the object to be destroy.
*
* @return NULL
*/
void dma_buf_destroy(ping_pong_buf_t *obj);
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif // __DMA_H__

Some files were not shown because too many files have changed in this diff Show more