123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428 |
- /*
- * File : drv_dmic.c
- * This file is part of RT-Thread RTOS
- * COPYRIGHT (C) 2008 - 2012, RT-Thread Development Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Change Logs:
- * Date Author Notes
- * 2015-11-19 Urey the first version
- */
- #include <rthw.h>
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <drivers/audio.h>
- #ifdef RT_USING_FINSH
- # include <finsh.h>
- #endif
- #include "board.h"
- #include "drv_gpio.h"
- #include "drv_dma.h"
- #include "drv_aic.h"
- #include "drv_clock.h"
- #include "drv_dmic.h"
- #include "dma.h"
- #include "audio_pipe.h"
- #define DMIC_DEBUG 0
- #if DMIC_DEBUG
- # define DMIC_DBG(...) rt_kprintf("[DMIC]"),rt_kprintf(__VA_ARGS__)
- #else
- # define DMIC_DBG(...)
- #endif
- #define DMIC_DMA_RX_CHAN 4
- #define DMIC_FIFO_DEPTH 64
- #define JZ_DMIC_FORMATS 16
- #define JZ_DMIC_RATE (8000)
- ALIGN(32) rt_uint32_t _g_dmic_dma_buffer[DMIC_DMA_PAGE_NUM*DMIC_DMA_PAGE_SIZE/sizeof(rt_uint32_t)];
- static struct jz_dmic _g_jz_dmic=
- {
- .io_base = DMIC_BASE,
- .dma_buf = (rt_uint8_t *)_g_dmic_dma_buffer,
- .dma_offset = 0,
- };
- static void dump_dmic_registers(void)
- {
- struct jz_dmic *jz_dmic = &_g_jz_dmic;
- rt_kprintf("DMICCR0 %p : 0x%08x\n", (jz_dmic->io_base+DMICCR0),dmic_read_reg(jz_dmic, DMICCR0));
- rt_kprintf("DMICGCR %p : 0x%08x\n", (jz_dmic->io_base+DMICGCR),dmic_read_reg(jz_dmic, DMICGCR));
- rt_kprintf("DMICIMR %p : 0x%08x\n", (jz_dmic->io_base+DMICIMR),dmic_read_reg(jz_dmic, DMICIMR));
- rt_kprintf("DMICINTCR %p : 0x%08x\n", (jz_dmic->io_base+DMICINTCR),dmic_read_reg(jz_dmic, DMICINTCR));
- rt_kprintf("DMICTRICR %p : 0x%08x\n", (jz_dmic->io_base+DMICTRICR),dmic_read_reg(jz_dmic, DMICTRICR));
- rt_kprintf("DMICTHRH %p : 0x%08x\n", (jz_dmic->io_base+DMICTHRH),dmic_read_reg(jz_dmic, DMICTHRH));
- rt_kprintf("DMICTHRL %p : 0x%08x\n", (jz_dmic->io_base+DMICTHRL),dmic_read_reg(jz_dmic, DMICTHRL));
- rt_kprintf("DMICTRIMMAX %p : 0x%08x\n", (jz_dmic->io_base+DMICTRIMMAX),dmic_read_reg(jz_dmic, DMICTRIMMAX));
- rt_kprintf("DMICTRINMAX %p : 0x%08x\n", (jz_dmic->io_base+DMICTRINMAX),dmic_read_reg(jz_dmic, DMICTRINMAX));
- rt_kprintf("DMICDR %p : 0x%08x\n", (jz_dmic->io_base+DMICDR),dmic_read_reg(jz_dmic, DMICDR));
- rt_kprintf("DMICFTHR %p : 0x%08x\n", (jz_dmic->io_base+DMICFTHR),dmic_read_reg(jz_dmic, DMICFTHR));
- rt_kprintf("DMICFSR %p : 0x%08x\n", (jz_dmic->io_base+DMICFSR),dmic_read_reg(jz_dmic, DMICFSR));
- rt_kprintf("DMICCGDIS %p : 0x%08x\n", (jz_dmic->io_base+DMICCGDIS),dmic_read_reg(jz_dmic, DMICCGDIS));
- return;
- }
- MSH_CMD_EXPORT(dump_dmic_registers,"dump dmic regs...\n");
- int jz_dmic_set_rate(struct jz_dmic* dmic, int rate)
- {
- // rt_kprintf("rate = %d\n",rate);
- switch (rate)
- {
- case 8000:
- __dmic_set_sr_8k(dmic);
- break;
- case 16000:
- __dmic_set_sr_16k(dmic);
- break;
- case 48000:
- __dmic_set_sr_48k(dmic);
- break;
- default:
- DMIC_DBG("dmic unsupport rate %d\n", rate);
- }
- return 0;
- }
- int jz_dmic_set_channels(struct jz_dmic* dmic, int channels)
- {
- if (channels > 4)
- channels = 4;
- if (channels <= 1)
- channels = 1;
- __dmic_set_chnum(dmic,channels - 1);
- }
- int jz_dmic_set_record_volume(struct jz_dmic* dmic, int vol)
- {
- if(vol >= 32)
- vol = 31;
- __dmic_set_gcr(dmic,vol);
- dmic->record_gain = vol;
- }
- static void jz_dmic_dma_complete(struct rt_dma_channel *dmac, struct dma_message *msg)
- {
- rt_base_t level;
- if(msg->complete_cb)
- msg->complete_cb(msg->complete_arg,msg->dst_addr);
- /* restart DMA Job */
- rt_dma_trans_message(dmac,msg);
- }
- void jz_dmic_start_recv(struct jz_dmic* dmic,void (*rx_callback)(void *,void *), void *rx_arg)
- {
- rt_base_t level;
- rt_uint32_t i;
- struct dma_message message;
- __dmic_enable_rdms(dmic);
- __dmic_enable(dmic);
- level = rt_hw_interrupt_disable();
- dmic->dma_offset = 0;
- dmic->dma_buf = (rt_uint8_t *)_g_dmic_dma_buffer;
- for (i = 0; i < DMIC_DMA_PAGE_NUM; ++i)
- {
- message.src_addr = (uint8_t *) (DMIC_BASE + DMICDR);
- message.src_option = RT_DMA_ADDR_FIX;
- message.dst_addr = (uint8_t *) (dmic->dma_buf + DMIC_DMA_PAGE_SIZE * i);
- message.dst_option = RT_DMA_ADDR_INC;
- message.t_size = DMIC_DMA_PAGE_SIZE;
- message.t_mode = JZDMA_REQ_DMIC_RX;
- /* init callback */
- message.complete_cb = rx_callback;
- message.complete_arg = rx_arg;
- rt_dma_trans_message(dmic->rx_dmac,&message);
- }
- rt_hw_interrupt_enable(level);
- return ;
- }
- void jz_dmic_stop_recv(struct jz_dmic* dmic)
- {
- if (__dmic_is_enable_rdms(dmic))
- {
- __dmic_disable_rdms(dmic);
- }
- __dmic_disable(dmic);
- }
- void dmic_rx_complete(void *data,void *pbuf)
- {
- struct jz_dmic *dmic = (struct jz_dmic *)data;
- rt_device_write(RT_DEVICE(&dmic->pipe),0,pbuf,DMIC_DMA_PAGE_SIZE);
- }
- #define CFG_DMIC_PIPE_SIZE (2 * 1024)
- struct jz_dmic* rt_hw_dmic_init(void)
- {
- struct jz_dmic *dmic = &_g_jz_dmic;
- //init pipe for record
- {
- rt_uint8_t *buf = rt_malloc(CFG_DMIC_PIPE_SIZE);
- if(buf == RT_NULL)
- {
- rt_kprintf("request pipe memory error\n");
- return RT_NULL;
- }
- rt_audio_pipe_init(&dmic->pipe,"recdmic",RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD,buf,(CFG_DMIC_PIPE_SIZE));
- rt_device_open(RT_DEVICE(&dmic->pipe),RT_DEVICE_OFLAG_RDONLY);
- }
- /* GPIO config
- * PB05 -> FUNC1 DMIC1_IN
- * PB21 -> FUNC0 DMIC_CLK
- * PB22 -> FUNC0 DMIC0_IN
- * */
- gpio_set_func(GPIO_PORT_B,GPIO_Pin_5,GPIO_FUNC_1);
- gpio_set_func(GPIO_PORT_B,GPIO_Pin_21,GPIO_FUNC_0);
- gpio_set_func(GPIO_PORT_B,GPIO_Pin_22,GPIO_FUNC_0);
- /* enable clock */
- dmic->clk_gate = clk_get("dmic");
- if (dmic->clk_gate == RT_NULL)
- {
- DMIC_DBG("Failed to get dmic gate clock \n");
- return RT_NULL;
- }
- clk_enable(dmic->clk_gate);
- /*gain: 0, ..., e*/
- __dmic_reset(dmic);
- while (__dmic_get_reset(dmic)) ;
- jz_dmic_set_rate(dmic, 8000);
- __dmic_set_chnum(dmic,0); //mono
- __dmic_enable_hpf1(dmic);
- __dmic_set_gcr(dmic, 27);
- __dmic_mask_all_int(dmic);
- __dmic_enable_pack(dmic);
- __dmic_enable_sw_lr(dmic);
- __dmic_enable_lp(dmic);
- __dmic_disable_lp(dmic);
- __dmic_set_request(dmic, 48);
- __dmic_enable_hpf2(dmic);
- __dmic_set_thr_high(dmic, 32);
- __dmic_set_thr_low(dmic, 16);
- __dmic_enable_tri(dmic);
- //config DMA
- {
- int trigger;
- /* DMA config */
- struct dma_config config;
- dmic->rx_dmac = rt_dma_get_channel(DMIC_DMA_RX_CHAN);
- if (dmic->rx_dmac != RT_NULL)
- {
- DMIC_DBG("config dmic dma rx channel...\n");
- config.direction = RT_DMA_DEV_TO_MEM;
- config.src_addr_width = RT_DMA_BUSWIDTH_2_BYTES;
- config.src_maxburst = (DMIC_FIFO_DEPTH * RT_DMA_BUSWIDTH_2_BYTES) / 2;
- config.dst_addr_width = RT_DMA_BUSWIDTH_2_BYTES;
- config.dst_maxburst = (64 * 1024);
- rt_dma_configture(dmic->rx_dmac, &config);
- dmic->rx_dmac->start = RT_NULL;
- dmic->rx_dmac->complete = jz_dmic_dma_complete;
- }
- trigger = config.src_maxburst / config.src_addr_width;
- __dmic_set_request(dmic, trigger);
- }
- jz_dmic_start_recv(dmic,dmic_rx_complete,dmic);
- return dmic;
- _error_exit:
- __dmic_disable(dmic);
- rt_audio_pipe_detach(&dmic->pipe);
- clk_disable(dmic->clk_gate);
- return RT_NULL;
- }
- //INIT_ENV_EXPORT(rt_hw_dmic_init);
- struct speech_wav_header
- {
- char riff_id[4]; //"RIFF"
- uint32_t size0; //file len - 8
- char wave_fmt[8]; //"WAVEfmt "
- uint32_t size1; //0x10
- uint16_t fmttag; //0x01
- uint16_t channel; //1
- uint32_t samplespersec; //8000
- uint32_t bytepersec; //8000 * 2
- uint16_t blockalign; //1 * 16 / 8
- uint16_t bitpersamples; //16
- char data_id[4]; //"data"
- uint32_t size2; //file len - 44
- };
- static void speech_wav_init_header(struct speech_wav_header *header,rt_uint16_t Channels,int SamplesPerSec,int BitsPerSample)
- {
- strcpy(header->riff_id, "RIFF");
- header->size0 = 0; // Final file size not known yet, write 0
- strcpy(header->wave_fmt, "WAVEfmt ");
- header->size1 = 16; // Sub-chunk size, 16 for PCM
- header->fmttag = 1; // AudioFormat, 1 for PCM
- header->channel = Channels; // Number of channels, 1 for mono, 2 for stereo
- header->samplespersec = SamplesPerSec; // Sample rate
- header->bytepersec = SamplesPerSec * BitsPerSample * Channels / 8; //Byte rate
- header->blockalign = Channels * BitsPerSample / 8; // Block align, NumberOfChannels*BitsPerSample/8
- header->bitpersamples = BitsPerSample;
- strcpy(header->data_id, "data");
- header->size2 = 0;
- }
- static void speech_wav_upgrade_size(struct speech_wav_header *header,rt_uint32_t paylodSize)
- {
- header->size0 = paylodSize + 36;
- header->size2 = paylodSize;
- }
- #include <finsh.h>
- #include <dfs_posix.h>
- rt_uint8_t rec_buff[2048];
- int dmic_record(int samplingrates)
- {
- struct jz_dmic *dmic = &_g_jz_dmic;
- rt_device_t dmic_pipe;
- struct speech_wav_header wav_header;
- rt_uint32_t wav_len = 0;
- char *file_name;
- int fd;
- int i = 0;
- int rdlen, wrlen;
- rt_kprintf("samplingrates = %d\n",samplingrates);
- if((samplingrates != 8000) && (samplingrates != 16000))
- {
- rt_kprintf("un-support this samplingrates\n");
- return -RT_EIO;
- }
- dmic_pipe = rt_device_find("recdmic");
- if(dmic_pipe == RT_NULL)
- {
- rt_kprintf("can't find the record device\n");
- return -RT_ERROR ;
- }
- rt_kprintf("pls hold WAKE key to start record...\n");
- while(gpio_get_value(GPIO_PORT_B, GPIO_Pin_31) == 1)
- rt_thread_delay(100);
- rt_kprintf("OK,start record....\n");
- if(samplingrates == 8000)
- file_name = "/appfs/dmic8k.wav";
- else
- file_name = "/appfs/dmic16k.wav";
- fd = open(file_name, O_WRONLY | O_CREAT | O_TRUNC, 0);
- if (fd < 0)
- {
- rt_kprintf("open file for write failed\n");
- return -RT_EIO;
- }
- speech_wav_init_header(&wav_header,1,samplingrates,16);
- write(fd, &wav_header, wav_len);
- jz_dmic_set_rate(dmic,samplingrates);
- wav_len = 0;
- while(i++ < 1000)
- {
- rdlen = rt_device_read(dmic_pipe,0,rec_buff,sizeof(rec_buff));
- wrlen = write(fd, rec_buff, rdlen);
- if (wrlen != rdlen)
- {
- rt_kprintf("write data failed\n");
- close(fd);
- return -RT_EIO;
- }
- wav_len += wrlen;
- if(gpio_get_value(GPIO_PORT_B, GPIO_Pin_31) == 1)
- break;
- }
- rt_kprintf("record complete...\n");
- //upgrage wav header
- lseek(fd,0,SEEK_SET);
- speech_wav_upgrade_size(&wav_header,wav_len);
- write(fd, &wav_header, sizeof(struct speech_wav_header));
- close(fd);
- rt_kprintf("WAV file saved ok!\n");
- }
- FINSH_FUNCTION_EXPORT(dmic_record,dmic record test);
- #if 0
- int dmic_test(void)
- {
- rt_device_t device;
- int i = 0;
- device = rt_device_find("recdmic");
- if(device == RT_NULL)
- {
- rt_kprintf("can't find the record device\n");
- return -RT_ERROR ;
- }
- audio_device_set_rate(8000);
- while(i++ < 1000)
- {
- int len;
- uint8_t *sendBuf;
- sendBuf = audio_device_get_buffer(&len);
- len = rt_device_read(device,0,sendBuf,len);
- audio_device_write(sendBuf,len);
- }
- rt_kprintf("dmic test complete...\n");
- return 0;
- }
- MSH_CMD_EXPORT(dmic_test,dmic test ....);
- #endif
|