Digitales MIC (es7202 PDM-Protokoll) MIC-Aufnahmeton ist gering

Frage: Unser Unternehmen hat ein Projekt, das Android 11 rk3566-Projekt, das ein Audiomodul hat, und das Projekt MIC verwendet es7202 (ADC). Dieser Chip ist ein Codierungschip und hat keine Decodierungsfunktion. Die Aufnahmeverstärkung dieses Moduls war auf das Maximum eingestellt. , aber die Lautstärke des aufgezeichneten Mikrofons ist immer noch sehr niedrig, und es gibt keine Lösung für die Hardware. Das digitale Mikrofon verwendet das PDM-Protokoll, und das digitale PDM-Signal ist komplizierter. PDM-Signale werden in meinen anderen Artikeln behandelt.

rk3566 Android11 ​​Konfiguration Soundkarte (es7202 ADC)_Android kann nicht fliegen Blog-CSDN blog_android Soundkarte

Analyse: MIC wird an die CPU gesendet, um das digitale MIC-Signal für ES7202 auszugeben. Bitte bestätigen Sie, ob es eine Verstärkungsverarbeitung für das digitale MIC-Signal in der CPU gibt. Theoretisch ja, das CPU-PDM-Datensignal akzeptiert standardmäßig Eingaben mit niedriger Amplitude, und die Verarbeitung des PDM-Signals in der CPU ist relativ kompliziert. Die auf der PDM-Schnittstelle basierende Anwendung reduziert die Komplexität des sendenden Geräts, und da der CODEC als empfangendes Gerät einen internen Dezimierungsfilter integriert, wird die Gesamtsystemkomplexität stark reduziert. Das PDM verwendet eine Takt-Abtastrate, die viel höher als die PCM-Abtastrate ist, um die analoge Komponente zu modulieren, und es wird nur 1 Bit ausgegeben, das entweder 0 oder 1 ist. Daher wird durch PDM dargestelltes digitales Audio auch als überabgetastetes 1-Bit-Audio bezeichnet. Verglichen mit einer Reihe von Nullen und Einsen in PDM ist das Quantisierungsergebnis von PCM intuitiver und einfacher. Die Verwendung des PDM-Verfahrens als Empfangsseite der Analog-Digital-Wandlung erfordert die Verwendung eines Dezimationsfilters (Dezimationsfilter), um die durch dicht gepackte Nullen und Einsen dargestellten Dichtekomponenten in Amplitudenkomponenten umzuwandeln, während das PCM-Verfahren bereits die Amplitude erhält Komponenten.

Lösungsrichtung: Da die Verstärkung unseres es7202 MIC auf das Maximum eingestellt wurde, gibt es immer noch keinen guten Effekt, und der Effekt der Erhöhung der MIC-Aufzeichnung kann nicht realisiert werden. Direkte Verarbeitung des PDM-Datensignals Aufgrund der vom DATA MIC eingegebenen Daten und der hohen Komplexität der PDM-Daten ist es für uns schwierig, die relevanten Daten zu verarbeiten, daher wenden wir die dritte Methode an, nämlich die Verarbeitung in tinyalsa, und die übergeordnete Android-Anwendung ruft den zugrunde liegenden Treiber auf Beim Fahren wird der zugrunde liegende Treiber über die HAL-Schicht aufgerufen, und die Hardware wird zum Laufen gebracht, und die Verarbeitung in der HAL-Schicht wird aufgerufen, da wir das Audio verwenden ALSA-Architektur, die obere Schicht ruft den Treiber über die relevanten PCM-Verarbeitungsfunktionen auf. Ich glaube, dass Sie mit Tinycap und Tinyplay mehr wissen. Wenn Sie nicht viel wissen, können Sie sich den entsprechenden Quellcode ansehen. Während unseres Debugging-Prozess verwenden wir weitere verwandte Befehle und analysieren weiter ... Und unser Audio-Sampling, PCM Wie sieht der Stream aus?Wenn es Mono ist, dann die Daten jedes Samples, hier betrachten wir die Daten als Integer-Daten, die ist eine Reihe, und jede Ganzzahl belegt 2 Bytes (16-Bit), 9 Abtastwerte sind 18 Bytes Daten. Die minimale ganzzahlige Größe jedes Samples beträgt -32768 und die maximale 32768 (Hinweis: Der Datentyp ist hier ein kurzer Typ). Wenn Sie ein Diagramm basierend auf der Position und dem Wert der abgetasteten Daten zeichnen, erhalten Sie ein wellenförmiges Diagramm wie das auf dem Player. Stereo ist tatsächlich eine Zweikanal-Abtastung, und wenn seine Daten als eine Datenfolge betrachtet werden, sind es tatsächlich die Daten des linken und des rechten Kanals, die verschachtelt sind, und jeder Rahmen ist ein 16-Bit-Abtastpunkt. Wir können also die erhaltenen PCM-Rohdaten verarbeiten, wenn auch der zugrunde liegende Treiber aufgerufen wird, und müssen sie nur noch vergrößern. Und das löst unser Problem: Das Prinzip besteht darin, die vom MIC aufgezeichneten PCM-Rohdaten als Sinuswelle zu betrachten, und was wir tun müssen, ist, die Amplitude der Sinuswelle zu verstärken, was einer Erhöhung der Lautstärke des PCM entspricht data. , müssen Sie nur alle abgetasteten Daten mit einem Koeffizienten multiplizieren.

Schauen wir uns zunächst den aufrufenden Funktionscode der HAL-Schicht an:

static int get_next_buffer(struct resampler_buffer_provider *buffer_provider,
                           struct resampler_buffer* buffer)
{
    struct stream_in *in;
    size_t i,size;

    if (buffer_provider == NULL || buffer == NULL)
        return -EINVAL;

    in = (struct stream_in *)((char *)buffer_provider -
                              offsetof(struct stream_in, buf_provider));

    if (in->pcm == NULL) {
        buffer->raw = NULL;
        buffer->frame_count = 0;
        in->read_status = -ENODEV;
        return -ENODEV;
    }

    if (in->frames_in == 0) {
        size = pcm_frames_to_bytes(in->pcm,pcm_get_buffer_size(in->pcm)
        in->read_status = pcm_read(in->pcm,//这里就调用了pcm_read,来起一个过度作用,其实是使用了tinyalsa,来获取原始pcm数据,(void*)in->buffer,中装入了PCM 原始数据。
                                   (void*)in->buffer,pcm_frames_to_bytes(in->pcm, in->config->period_size));
        if (in->read_status != 0) {
            ALOGE("get_next_buffer() pcm_read error %d", in->read_status);
            buffer->raw = NULL;
            buffer->frame_count = 0;
            return in->read_status;
        }

        //fwrite(in->buffer,pcm_frames_to_bytes(in->pcm,pcm_get_buffer_size(in->pcm)),1,in_debug);
        in->frames_in = in->config->period_size;

        /* Do stereo to mono conversion in place by discarding right channel */
        if ((in->channel_mask == AUDIO_CHANNEL_IN_MONO)
                &&(in->config->channels == 2)) {
            //ALOGE("channel_mask = AUDIO_CHANNEL_IN_MONO");
            for (i = 0; i < in->frames_in; i++)
                in->buffer[i] = in->buffer[i * 2];
        }
    }

    //ALOGV("pcm_frames_to_bytes(in->pcm,pcm_get_buffer_size(in->pcm)):%d",size);
    buffer->frame_count = (buffer->frame_count > in->frames_in) ?
                          in->frames_in : buffer->frame_count;
    buffer->i16 = in->buffer +
                  (in->config->period_size - in->frames_in) *
                  audio_channel_count_from_in_mask(in->channel_mask);

    return in->read_status;

}

Schauen wir uns noch einmal den Code in tinyalsa an: Was ich hier hauptsächlich gebe, ist der Code, der sich auf den Input-Stream bezieht, also beim Aufnehmen, und der Playback-Stream ist das Gegenteil.

int pcm_read(struct pcm *pcm, void *data, unsigned int count)
{
    struct snd_xferi x;

    if (!(pcm->flags & PCM_IN))
        return -EINVAL;
    
    x.buf = data;
    x.frames = count / (pcm->config.channels *
                        pcm_format_to_bits(pcm->config.format) / 8);

    for (;;) {
        if (!pcm->running) {
            if (pcm_start(pcm) < 0) {
                fprintf(stderr, "start error");
                return -errno;
            }
        }
        if (ioctl(pcm->fd, SNDRV_PCM_IOCTL_READI_FRAMES, &x)) {//用户层通过ioctl的方式来调用kernel,//读出入初始化数据,即录音。
            pcm->prepared = 0;
            pcm->running = 0;
            if (errno == EPIPE) {
                    /* we failed to make our window -- try to restart */
                pcm->underruns++;
                continue;
            }
            return oops(pcm, errno, "cannot read stream data");
        }

        if (pcm->config.channels == 2) {
            if (channalFlags == -1 ) {
                if (startCheckCount < SAMPLECOUNT) {
                    startCheckCount += count;
                } else {
                    channalFlags = channel_check(data,count / 2);
                }
            }

            channel_fixed(data,count / 2, channalFlags);
        }

        return 0;
    }
}

Die Implementierung der Kernel-Schicht initiiert einen Systemaufruf im Kernel, um den fops-Funktionssatz auszuführen, der vom Benutzerraum hätte initiiert werden sollen.

Kernel Kernelversion, 4.19.172

PCM逻辑设备文件操作函数集:snd_pcm_f_ops[]
PCM逻辑设备文件操作函数集对于Playback和Capture是分开定义的,该操作函数集如下:

const struct file_operations snd_pcm_f_ops[2] = {
        {
                .owner =                THIS_MODULE,
                .write =                snd_pcm_write,//用于单通道音频信号写
                .write_iter =           snd_pcm_writev, 
                .open =                 snd_pcm_playback_open,
                .release =              snd_pcm_release,
                .llseek =               no_llseek,
                .poll =                 snd_pcm_poll,
                .unlocked_ioctl =       snd_pcm_ioctl,//用于多通道音频信号写
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
                .get_unmapped_area =    snd_pcm_get_unmapped_area,
        },
        {
                .owner =                THIS_MODULE,
                .read =                 snd_pcm_read,//用于单通道音频信号读
                .read_iter =            snd_pcm_readv,
                .open =                 snd_pcm_capture_open,
                .release =              snd_pcm_release,
                .llseek =               no_llseek,
                .poll =                 snd_pcm_poll,
                .unlocked_ioctl =       snd_pcm_ioctl,//用于多通道音频信号读
                .compat_ioctl =         snd_pcm_ioctl_compat,
                .mmap =                 snd_pcm_mmap,
                .fasync =               snd_pcm_fasync,
                .get_unmapped_area =    snd_pcm_get_unmapped_area,
        }
};

 

        Werfen wir einen Blick auf den Hardware-Schaltplan unseres es7202, sowie das Frame-Diagramm und zugehörige Register zum Einstellen der Verstärkung.

es7202 internes Rahmendiagramm:

es7202 Peripherieschaltung, relativ wenige:

 

Das es7202-interne Modulations-MIC-Verstärkungsregister: 

 

        Insgesamt sind die Gesamtvorteile der Verwendung von digitalem MIC daher ziemlich offensichtlich: Es gibt weniger Peripherieschaltkreise, und die eingegebenen MIC-Daten werden mit der Sammlung von CLK in PDM-DATEN gemischt und direkt über die PDM-Datenschnittstelle an die CPU gesendet wird bearbeitet. 

Der modifizierte Patch ist unten angegeben, und das Verzeichnis befindet sich in external/tinyalsa/pcm.c

diff --git a/pcm.c b/pcm.c
index 0b97bbc..01d777e 100644
--- a/pcm.c
+++ b/pcm.c
@@ -635,13 +635,36 @@ void channel_fixed(void *data, unsigned len, int chFlag)
     return;
 }
 
+static short out_vol = 4.0;//扩大音量倍数
+static void volume_process(const void *buffer, size_t length, short volume) {
+
+short * buffer_end = (short*)buffer + length/2;
+       short * pcmData = (short *)buffer;
+          int i = 0;
+       int pcmval;
+
+       while (pcmData < buffer_end) {
+               pcmval = (short)*pcmData * volume;
+                if (pcmval < 32768 && pcmval > -32768) {
+                        *pcmData = pcmval;
+                } else if (pcmval > 32767) {
+                        *pcmData = 32767; //限制最大幅度
+                } else if (pcmval < -32767) {
+                        *pcmData = -32767;//限制最小幅度
+                }
+                
+            ++pcmData;
+           i++;
+       }
+}
+
 int pcm_read(struct pcm *pcm, void *data, unsigned int count)
 {
     struct snd_xferi x;
 
     if (!(pcm->flags & PCM_IN))
         return -EINVAL;
-
+       memset(data, 0, count);
     x.buf = data;
     x.frames = count / (pcm->config.channels *
                         pcm_format_to_bits(pcm->config.format) / 8);
@@ -676,6 +699,7 @@ int pcm_read(struct pcm *pcm, void *data, unsigned int count)
             channel_fixed(data,count / 2, channalFlags);
         }
 
+       volume_process(x.buf, count , out_vol);
         return 0;
     }
 }

 Theoretisch kann dieser Patch auch das Problem der niedrigen Eingangs-Mikrofon-Aufnahmelautstärke lösen, die durch andere Codecs verursacht wird.

Supongo que te gusta

Origin blog.csdn.net/qq_48709036/article/details/124991843
Recomendado
Clasificación