STM32 DAC wav player

Başlatan Emin ATEŞ, 20 Eylül 2019, 10:20:26

Emin ATEŞ

Merhaba,
Stm32g071kbt6 mikrokontrolör, n8002 amplifier, spi flash içeren bir kart tasarladım. Kart elime ulaştı ve speaker için küçük bir dac örneği hazırladım. Wav formatında bir dosyayı bilgisayar ortamında decode edip raw datasını 12bit daca verebileceğim şekilde düzenledikten sonra mikrokontrolör üzerinde koşturmaya çalıştım. Speakerdan gelen sesin ne olduğu anlaşılsa da ciddi anlamda gürültü var. Bunun için 440hzlik(A notası) sinüs oluşturarak dacın çıkışını kontrol ettiğimde sinüsün gayet temiz olduğunu gördüm. Dac output bufferı kapatsam da açsam da pek bir şey değişmedi. Devre üzerinde ki amplifier haricinde, pam8403 ü modül olarak denediğimde aynı sonuçla karşılaştım. Gürültü bass seslerde daha çok oluyor gibi geldi. Sorunun yazılım tarafında olmadığı kanaatindeyim. Donanım kısmında pek bilgim olmadığı için yorum getiremiyorum ve araştırma yapamıyorum. Donanımsal olarak aklıma çıkış empedansı geldi ama devamını getiremiyorum. Şimdiden yardımlarınız için teşekkürler.

Ek bilgiler;

Sinüs sinyali;


image upload

C# wav dosyasını decode etme;
using System;
using System.Collections.Generic;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {

        struct WavHeader
        {
            public byte[] riffID; 
            public uint size; 
            public byte[] wavID;
            public byte[] fmtID;
            public uint fmtSize;
            public ushort format; 
            public ushort channels;
            public uint sampleRate; 
            public uint bytePerSec; 
            public ushort blockSize;
            public ushort bit;
            public byte[] dataID;
            public uint dataSize;
        }



        static void Main(string[] args)
        {
            ushort Map(ushort x, ushort in_min, ushort in_max, ushort out_min, ushort out_max)
            {
                return (ushort)(((int)x - (int)in_min) * ((int)out_max - (int)out_min) / ((int)in_max - (int)in_min) + (int)out_min);
            }
            WavHeader Header = new WavHeader();
            List<ushort> lDataList = new List<ushort>();
            List<ushort> rDataList = new List<ushort>();

            using (FileStream fs = new FileStream(@"test4.wav", FileMode.Open, FileAccess.Read))
            using (BinaryReader br = new BinaryReader(fs))
            {
                try
                {
                    Header.riffID = br.ReadBytes(4);
                    Header.size = br.ReadUInt32();
                    Header.wavID = br.ReadBytes(4);
                    Header.fmtID = br.ReadBytes(4);
                    Header.fmtSize = br.ReadUInt32();
                    Header.format = br.ReadUInt16();
                    Header.channels = br.ReadUInt16();
                    Header.sampleRate = br.ReadUInt32();
                    Header.bytePerSec = br.ReadUInt32();
                    Header.blockSize = br.ReadUInt16();
                    Header.bit = br.ReadUInt16();
                    Header.dataID = br.ReadBytes(4);
                    Header.dataSize = br.ReadUInt32();

                    for (int i = 0; i < Header.dataSize / Header.blockSize; i++)
                    {
                        lDataList.Add((ushort)br.ReadUInt16());
                      //  rDataList.Add((ushort)br.ReadUInt16());
                    }
                }
                finally
                {
                    if (br != null)
                    {
                        br.Close();
                    }
                    if (fs != null)
                    {
                        fs.Close();
                    }
                }
            }
            string write = "#include \"stdint.h\"\n\n#define _AMP(x) x/8\n\nconst uint16_t sound[" + 2850 * 16 + "] = {\n";
            for (int i = 0; i < 2850; i++)
            {
                write += "\t";
                for (int j = 0; j < 16; j++)
                {
                    lDataList[i * 16 + j] = Map(lDataList[i * 16 + j], 0, 0xffff, 0,0xfff);
                    write += "_AMP(0x" + ((lDataList[i * 16 + j] < 0x10) ? "000" : (lDataList[i * 16 + j] < 0x100) ? "00": (lDataList[i * 16 + j] < 0x1000) ? "0":"" ) + lDataList[i * 16 + j].ToString("X") + "),";
                }
                write += "\n";
            }
            write += "};";
            System.IO.File.WriteAllText(@"test.c", write);
            


            return;
        }

    }
}

C# sinüs datası oluşturma;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace simpleSineWaveGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            double pi = 3.14159265359f;
            int sampleRate = 440;
            int column = 10;
            ushort[] sine = new ushort[sampleRate];
            for(double i=0;i< sampleRate; i++)
            {
                sine[(int)i] = (ushort)(Math.Sin((2 * pi) * (i / sampleRate))*2047+2048);
            }

            string write = "#include \"stdint.h\"\n\n#define _AMP(x) ( x / 4 )\n\nconst uint16_t sound[" + sampleRate + "] = {\n";
            for (int i = 0; i - 1 < sampleRate / column; i++)
            {
                write += "\t";
                for (int j = 0; j < column; j++)
                {
                    if ((i * column) + j >= sampleRate)
                        break;
                    write += "_AMP(0x" + ((sine[i * column + j] < 0x10) ? "000" : (sine[i * column + j] < 0x100) ? "00" : (sine[i * column + j] < 0x1000) ? "0" : "") + sine[i * column + j].ToString("X") + "),";

                }
                write += "\n";
            }
            write += "};";
            System.IO.File.WriteAllText(@"test.c", write);


            Console.ReadLine();
        }
    }
}


Dac-DMA ayarları

   RCC->IOPENR   |= RCC_IOPENR_GPIOAEN;
   RCC->AHBENR   |= RCC_AHBENR_DMA1EN;
   RCC->APBENR1  |= ( RCC_APBENR1_DAC1EN |
                      RCC_APBENR1_TIM6EN );
   
    GPIOA->MODER    &= ~( 0x3 << ( 4 * 2 ) );
    GPIOA->MODER    |=  ( 0x3 << ( 4 * 2 ) );
    
    uint32_t dma_ccr_clr = ~( DMA_CCR_MEM2MEM |
                              DMA_CCR_PL |
                              DMA_CCR_MSIZE |
                              DMA_CCR_PSIZE |
                              DMA_CCR_PINC |
                              DMA_CCR_EN );
    uint32_t dma_ccr_set =  ( ( 0x2 << DMA_CCR_PL_Pos ) |
                              ( 0x1 << DMA_CCR_MSIZE_Pos ) |
                              ( 0x1 << DMA_CCR_PSIZE_Pos ) |
                              DMA_CCR_MINC |
                              DMA_CCR_CIRC |
                              DMA_CCR_DIR );
    DMA1_Channel1->CCR &= dma_ccr_clr;
    DMA1_Channel1->CCR |= dma_ccr_set;
    
    DMAMUX1_Channel0->CCR &= ~( DMAMUX_CxCR_DMAREQ_ID );
    DMAMUX1_Channel0->CCR |=  ( 0x8 << DMAMUX_CxCR_DMAREQ_ID_Pos );
    
    DMA1_Channel1->CMAR  = ( uint32_t )&sound;
    
    DMA1_Channel1->CPAR  = ( uint32_t )&( DAC1->DHR12R1 );
    
    DMA1_Channel1->CNDTR = ( uint16_t )SINE_SAMPLES;
    
    DMA1_Channel1->CCR |= ( DMA_CCR_EN );
    
    TIM6->PSC  =  0x0;//( 4);
    TIM6->ARR  =  ( SystemCoreClock / ( 440 * SINE_SAMPLES ) );//333;
    
    TIM6->CR2 &= ~( TIM_CR2_MMS );
    TIM6->CR2 |=  ( 0x2 << TIM_CR2_MMS_Pos );
    
    TIM6->CR1 |=  ( TIM_CR1_CEN );
    
    DAC1->CR  &= ~( DAC_CR_TSEL1 );
    DAC1->CR  |=  ( 0x5 << DAC_CR_TSEL1_Pos );
    
    DAC1->MCR = 2;
    
    DAC1->CR  |=  ( DAC_CR_DMAEN1 );
    
    DAC1->CR  |=  ( DAC_CR_EN1 );
    
    delay_cycles( 1000 );
    
    DAC1->CR  |=  ( DAC_CR_TEN1 );

Baybars

İyi çalışmalar
Şuan bende dac kullanarak hopalore ses vermeye çalışıyorum. Benim sorum ses sinayli decode ettikten sonra dac çıkışına nasıl veriyorsunuz? hazır bir kaç entegre buldum onlarla yapabilirim lakin direkt dac ile yapmak istiyorum. DAC'ı tetiklediğiniz timer değerleri nedir? DMA kullanmassam ne olur. Örneğin ben const olarak bir diziye ufak bir ses dosyasının hexi kaydedip ve bu değerleri timer kesmesiyle for döngüsünde bir bir arttırıp çıkışa versem yanlış olurmu?

Erol YILMAZ

Basit tema:
Ses örneğini belli bir periyotla FLASH'tan okuyup DAC'a göndermek...

Ne kadar sık göndermeliyiz konusu tamamen istenilen kalite ile alakalı.
Örneğin CD kalitesi sn'de 44100 kere 16 bit çözünürlüklü DAC çıkışı gerektirir...

Okan AKÇA

Bu is için yapılmış entegreler var flash bellek takip istediğiniz konusmayi seçip ses olarak cikis veriyor.