Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F103VET6 + DAC + DMA + SDIO + FATFS = WAV
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
loreal1970
Ребята помогите! Не могу воспроизвести wav с карточки.
Хочу сказать фразу по нажатию кнопки.
Карта читается.
Проблема то ли с ЦАП-ом, то ли выводом данных. В общем лыжи наглухо в асфальте.
Вот инит ЦАПа:
CODE
void Init_Sound(void)
{
DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM6, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseStructure.TIM_Period = 72-1; //
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);

TIM_SelectOutputTrigger(TIM6, TIM_TRGOSource_Update);

DMA_DeInit(DMA2_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR8R1;
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &WAVBuffer[0];
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize =512;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Channel3, &DMA_InitStructure);

DMA_Cmd(DMA2_Channel3, ENABLE);

DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = 0;
DAC_InitStructure.DAC_Trigger = DAC_Trigger_T6_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);

DAC_Cmd(DAC_Channel_1, ENABLE);

DAC_DMACmd(DAC_Channel_1, ENABLE);

TIM_Cmd(TIM6, DISABLE);
}


Дальше в основном цикле.

Код
if(Kn_a==1)    // Kn_a находится в прерывании
{
   Init_Sound();
   load_header();   // Здесь читаются заголовки WAV и настраивается таймер
   sound();
   Kn_a=0;
}


А вот с функцией sound(); наверное проблемы.

Код
void sound(void)
{
   while(1)
      {
         TIM_Cmd(TIM6, ENABLE);
      while(!(DMA2->ISR & DMA_ISR_HTIF3)) {}  

     f_read (&fsrc, &WAVBuffer[0], 256, &rb);
       DAC_SetChannel1Data(DAC_Align_8b_R, WAVBuffer[0]);
  

     if(rb < 256) {TIM_Cmd(TIM6, DISABLE); break;}  

     while(!(DMA2->ISR & DMA_ISR_TCIF3)) {}

     f_read (&fsrc, &WAVBuffer[256], 256, &rb);
       DAC_SetChannel1Data(DAC_Align_8b_R, WAVBuffer[256]);

     if(rb < 256) {TIM_Cmd(TIM6, DISABLE); break;}
       }
}


В динамике треск и писк.
В общем мозги кипят.
Прошу помощи, кто знает. Нужно проиграть мелодию с карточки.
jcxz
Вначале научитесь хотя-бы простой тональный сигнал на ЦАП выводить без всяких WAV.
loreal1970
Совет, конечно, хороший.
Я с этого начинал.
Вывел на динамик синус из таблицы.
Дело в другом.

Карта читается - я из нее вывожу картинку на ТФТ.

Сегодня записал на карту синус и попробовал вывести. И не получилось.
Вот посмотрите правильно или нет?
Код
f_lseek(&fsrc, 44);                                      // переходим на данные

while(1)
{
f_read (&fsrc, &WAVBuffer[0], 256, &rb);        // загружаем первую часть буфера
if(rb < 256) { break;}
while(!(DMA2->ISR & DMA_ISR_HTIF3)) {}     // ждем флаг
DMA2->IFCR |= DMA_ISR_HTIF3;                  // сбросить флаг

f_read (&fsrc, &WAVBuffer[256], 256, &rb);   // загружаем вторую часть буфера
if(rb < 256) { break;}
while(!(DMA2->ISR & DMA_ISR_TCIF3)) {}    // ждем флаг
DMA2->IFCR |= DMA_ISR_HTIF3;                 //сбросить флаг
}

Если что то не так, или все не так, не надо сразу лицом в грязь.
Просто подскажите как правильно.
mantech
Цитата(loreal1970 @ Apr 29 2015, 15:01) *
Сегодня записал на карту синус и попробовал вывести. И не получилось.


Я делал не так, закольцовывал дма буфер, с автоперезагрузкой, ставил флаг сработки на половине буфера и начале, дма в режиме прерывания, а в программе ждал сработки флагов, чтоб заполнить высвободившуюся часть буфера и т.д.
loreal1970
Благодарю mantech !

А можно по подробнее с настройками?
mantech
Цитата(loreal1970 @ Apr 29 2015, 15:50) *
А можно по подробнее с настройками?


Завтра гляну, если не забыл, где там все было biggrin.gif
loreal1970
В общем записал на карту синус (сформированный в программе Audacity 1кгц, 8 бит)
Начинаю читать, на экране осциллографа какой то кривой прямоугольник валит.
Вот настройка с выводом. Что не так? Прошу помощи.
CODE
void Init_Sound(void)
{
/* const uint16_t sinus_12bit[180]={
2048, 2119, 2191, 2262, 2333, 2404, 2474, 2543, 2613, 2681, 2748, 2815, 2881, 2946, 3009, 3072, 3133, 3193, 3252, 3309,
3364, 3418, 3471, 3521, 3570, 3617, 3662, 3705,
3746, 3785, 3822, 3856, 3889, 3919, 3947, 3972, 3996, 4017, 4035, 4051, 4065, 4076, 4085, 4091, 4095, 4095, 4095, 4091,
4085, 4076, 4065, 4051, 4035, 4017, 3996, 3972,
3947, 3919, 3889, 3856, 3822, 3785, 3746, 3705, 3662, 3617, 3570, 3521, 3471, 3418, 3364, 3309, 3252, 3193, 3133, 3072,
3009, 2946, 2881, 2815, 2748, 2681, 2613, 2543,
2474, 2404, 2333, 2262, 2191, 2119, 2048, 1977, 1905, 1834, 1763, 1692, 1622, 1553, 1483, 1415, 1348, 1281, 1215, 1150,
1087, 1024, 963, 903, 844, 787, 732, 678, 625,
575, 526, 479, 434, 391, 350, 311, 274, 240, 207, 177, 149, 124, 100, 79, 61, 45, 31, 20, 11, 5, 1, 0, 1, 5, 11, 20, 31, 45, 61,
79, 100, 124, 149, 177, 207, 240, 274,
311, 350, 391, 434, 479, 526, 575, 625, 678, 732, 787, 844, 903, 963, 1024, 1087, 1150, 1215, 1281, 1348, 1415, 1483, 1553,
1622, 1692, 1763, 1834, 1905, 1977
};*/


DAC_InitTypeDef DAC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC | RCC_APB1Periph_TIM2, ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);

TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseStructure.TIM_Period = (72000000/8000)-1;
TIM_TimeBaseStructure.TIM_Prescaler = 0;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);

DMA_DeInit(DMA2_Channel3);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&DAC->DHR8R1; // (uint32_t) & DAC->DHR12R1
DMA_InitStructure.DMA_MemoryBaseAddr = (u32) &WAVBuffer[0]; // sinus_12bit
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 512; // (sizeof(sinus_12bit) / sizeof(sinus_12bit[0]))
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte; // DMA_PeripheralDataSize_HalfWord
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte; // DMA_MemoryDataSize_HalfWord
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA2_Channel3, &DMA_InitStructure);

DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO;
DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; // DAC_OutputBuffer_Disable;
DAC_Init(DAC_Channel_1, &DAC_InitStructure);

DAC_DMACmd(DAC_Channel_1, ENABLE);
DAC_Cmd(DAC_Channel_1, ENABLE);
DMA_Cmd(DMA2_Channel3, ENABLE);

TIM_Cmd(TIM2, ENABLE); //TIM_Cmd(TIM2, DISABLE);
}


Код
void sound(void)
{
  
   disk_initialize(0);
   f_mount(0,&fs);
   f_open( &fsrc, "200.wav", FA_READ );
        f_read (&fsrc, &WAVBuffer, 512, &rb);
   f_lseek(&fsrc, 44);
  
   while(1)
      {
         while(!(DMA2->ISR & DMA_ISR_HTIF3)) {}
         f_read (&fsrc, &WAVBuffer[0], 256, &rb);
         DMA2->IFCR |= DMA_ISR_HTIF3;  
         if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}
        
         while(!(DMA2->ISR & DMA_ISR_TCIF3)) {}
         f_read (&fsrc, &WAVBuffer[256], 256, &rb);  
         DMA2->IFCR |= DMA_ISR_HTIF3;
         if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}
       }
}


Сама задача

Код
static  void  Task_AudioOUT (void *p_arg)
{
    (void)p_arg;
    OSTimeDlyHMSM(0, 0, 2, 250);
    Status = SD_Init();
    Status = SD_GetCardInfo(&SDCardInfo);
    Status = SD_SelectDeselect((uint32_t) (SDCardInfo.RCA << 16));
    Status = SD_EnableWideBusOperation(SDIO_BusWide_4b);
    Status = SD_SetDeviceMode(SD_DMA_MODE);
  
   while(1)
  {  
      if(Kn_a==1)                  // Флаг кнопки меняется в прерывании
      {
        
         Init_Sound();
        
         sound();
         Kn_a=0;
      }
      
      OSTimeDlyHMSM(0, 0, 1, 250);
   }
}



С массива, который в функции Init_Sound(), синус на осциллографе хороший.
Как начинаю с карты читать записанный синус, лезет какой то бред.
Может подскажите , добрые люди, где запятая не там стоит help.gif
AHTOXA
Так в wav-файле же не просто отсчёты для синуса, там ещё какой-то заголовок наверное?
loreal1970
Хорошо. Вот так я читаю заголовок. Изменений никаких. В посте выше я просто переместил указатель на 44 байта.

CODE
static
DWORD load_header (void) /* 0:Invalid format, 1:I/O error, >1:Number of samples */
{

DWORD ChunkID, SamplingRate, sz, Length;
char str[20];

//------------------------------------------------
f_mount(0,&fs);
f_open( &fsrc, "200.wav", FA_READ );
//------------------------------------------------
GUI_SetColor(GUI_WHITE); //RED
GUI_SetFont(&GUI_Font24_1);
GUI_DispStringAt(">", 0, 50);

if (f_read(&fsrc, Buff, 12, &rb)) return 1; /* Load file header (12 bytes) */
if (rb != 12 || LD_DWORD(Buff+8) != FCC('W','A','V','E')) return 0;
GUI_DispNextLine(); GUI_DispString("WAV File found:");

while(1) {
f_read(&fsrc, Buff, 8, &rb); /* Get Chunk ID and size */
if (rb != 8) return 0;
ChunkID = LD_DWORD(&Buff[0]);
sz = LD_DWORD(&Buff[4]); /* Chunk size */
//------------------------------
sprintf(str, "%ld", sz);
GUI_DispNextLine();
GUI_DispString(str);
//------------------------------
switch (ChunkID) { /* FCC */
case fmt_chunk: /* 'fmt ' chunk */
if (sz > 100 || sz < 16) return 0; /* Check chunk size */
f_read(&fsrc, Buff, sz, &rb); /* Get content */
if (rb != sz) return 0;
if (Buff[0] != 1) return 0; /* Check coding type (PCM=1) */

NumChannels = Buff[2]; /* Get channel flag */
if (NumChannels != 1 && NumChannels != 2) /* Check channels (1/2) */
return 0;
if(NumChannels == 1) {GUI_DispNextLine(); GUI_DispString("Mono");}
else if(NumChannels == 2) {GUI_DispNextLine(); GUI_DispString("Stereo");}

BitsPerSample = Buff[14]; /* Resolution flag */
if (BitsPerSample != 8 && BitsPerSample != 16) /* Check resolution (8/16) */
return 0;
if(BitsPerSample == 8) {GUI_DispNextLine(); GUI_DispString("8-bits");}
else if(BitsPerSample == 16) {GUI_DispNextLine(); GUI_DispString("16-bits");}

SamplingRate = LD_DWORD(Buff+4);
// set_sampling_rate( SamplingRate ); /* Sampling freq */
sprintf(str, "%ldHz", SamplingRate);
GUI_DispNextLine(); GUI_DispString(str);
break;

case data_chunk: /* 'data' chunk (start to play) */
Length = sz / (SamplingRate * NumChannels * (BitsPerSample>>3) ); // length in seconds
sprintf(str, "%ld:%2ld min", (Length/60), (Length%60));
GUI_DispNextLine(); GUI_DispString(str);
return sz;

case LIST_chunk: /* 'LIST' chunk (skip) */

case fact_chunk: /* 'fact' chunk (skip) */
f_lseek(&fsrc, (fsrc.fptr + sz));

break;

default : /* Unknown chunk (error) */
return 0;
}
}
//return 0;
}


и дальше

Код
void sound(void)
{
f_read (&fsrc, &WAVBuffer[0], 512, &rb);
    
    while(1)  
        {
            while(!(DMA2->ISR & DMA_ISR_HTIF3)) {}
            f_read (&fsrc, &WAVBuffer[0], 256, &rb);
            DMA2->IFCR |= DMA_ISR_HTIF3;    
            if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}
            
            while(!(DMA2->ISR & DMA_ISR_TCIF3)) {}
            f_read (&fsrc, &WAVBuffer[256], 256, &rb);    
            DMA2->IFCR |= DMA_ISR_HTIF3;
            if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}
         }
}


Исправил
while(1)
{
while(!(DMA2->ISR & DMA_ISR_HTIF3)) {}
f_read (&fsrc, &WAVBuffer[0], 256, &rb);
DMA2->IFCR |= DMA_ISR_HTIF3;
if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}

while(!(DMA2->ISR & DMA_ISR_TCIF3)) {}
f_read (&fsrc, &WAVBuffer[256], 256, &rb);
DMA2->IFCR |= DMA_ISR_TCIF3; //
if(rb < 256) {TIM_Cmd(TIM2, DISABLE); break;}
}

Все равно на экране беспорядочные значения
AHTOXA
Цитата(loreal1970 @ Apr 30 2015, 14:48) *
Хорошо. Вот так я читаю заголовок. Изменений никаких. В посте выше я просто переместил указатель на 44 байта.

Ок. Значит, вы уверены, что у вас считываются именно отсчёты синуса?
Тогда следующее замечание: зачем вы изменили размер периферии? (DMA_PeripheralDataSize_HalfWord на DMA_PeripheralDataSize_Byte)
Ведь размер регистра ЦАП не изменяется.
А, понял. Регистр поменялся тоже.
Ну тогда не знаю... Попробуйте записать в файл прямо тот же синус, который работает, многократно. И считайте его. Чтобы исключить ошибки обработки wav.
loreal1970
Так секундочку. Я чего то не понимаю.
В заголовке у меня получается
Сигнал моно, 16-бит, 8000Гц, размер и время.


Ребят! Может поделитесь рабочим примером чтения WAV с карты.
Что то совсем не получается.
В общем заголовок на экран вывожу.
А сами данные не получается вывести. Плиз.
adnega
Цитата(loreal1970 @ Apr 30 2015, 14:34) *
Так секундочку. Я чего то не понимаю.
В заголовке у меня получается
Сигнал моно, 16-бит, 8000Гц, размер и время.


Ребят! Может поделитесь рабочим примером чтения WAV с карты.
Что то совсем не получается.
В общем заголовок на экран вывожу.
А сами данные не получается вывести. Плиз.

Добавляйте к считанному с wav +0x8000 и сдвигайте на 4, чтоб получить 12 бит.

И непонятно как вы "разруливаете" ситуацию с тем, что данные в wav 16-битные?
В функциях чтения у вас 256 это байт?

А в DAC вы пишете байтами.
controller_m30
Пусть функция загрузки данных в DAC - укладывает выходные данные и в память тоже. Много не надо, первых 20-30 байт (или слов?) достаточно.
Затем сравните первые 20-30 семплов из WAV файла, с тем что отправилось в DAC.

Вот например кусочек на 18 семплов из Audacity в формате "WAV signed 16 bit PCM", и те-же данные как их видно в WINHEXе.
На второй картинке график в Excel построенный по тем-же 16 битным значениям (с прибавлением + 0x8000, как предлагает adnega).

Проверьте у себя, как работает функция преобразования данных для DAC. Или выложите здесь для сравнения, что читаете из WAV файла и что пишете в DAC.
MiklPolikov
Заголовок незачем читать, ели точно известно, в каком формате записан файл.
Но работая с 16и битным файлом, Вы не знаете, правильно ли задали смещение при чтении: быть может в выборку ЦАП у Вас попадает 1й байт из одного 16и битного значения и 2ой байт из следующго 16и битного значения, и поэтому на выходе ЦАП непонятная белиберда. Что бы исключить эту ошибку, запишите файл в 8и битном формате. И читайте его побайтно, побайтно отправляйте в ЦАП.
loreal1970
Да ребята. Вы правы. WAV у меня 16 битный. А преобразование неправильное.
Я так понимаю?
1. Заводим буфер на (к примеру 1024 байт)
2. Настраиваем таймер на частоту выборки семплов.
3. В прерывании таймера читаем половину буфера (по счетчику), сдвигаем каждое uint16_t слово на >>4 (приводим к 12 битам)
4. Выкладываем в DAC (настроенный на 12 битный режим)
5. Далее вторая половинка буфера.

Такой вариант (с некоторыми изменениями приемлем), но в DMA есть хороший режим, т.е. прерывание на половине и конце буфера.
Осталось теперь соединить это в кучу.
Вроди бы просто. Но что то перемкнуло и не могу сдвинуться с места.
adnega
Цитата(loreal1970 @ May 2 2015, 16:52) *
4. Выкладываем в DAC (настроенный на 12 битный режим)

Но не забываем, что данные в wav хранятся в знаковом формате, а в DAC нужно писать беззнаковые числа.
Quasar
Цитата(loreal1970 @ May 2 2015, 16:52) *
Такой вариант (с некоторыми изменениями приемлем), но в DMA есть хороший режим, т.е. прерывание на половине и конце буфера.


Еще в DMA есть режим с двумя буферами, Double Buffer Mode, я использую его для воспроизведения или записи чего-либо.

Цитата(loreal1970 @ May 2 2015, 16:52) *
3. В прерывании таймера читаем половину буфера (по счетчику), сдвигаем каждое uint16_t слово на >>4 (приводим к 12 битам)
4. Выкладываем в DAC (настроенный на 12 битный режим)
5. Далее вторая половинка буфера.


Но вы должны выдвигать данные в DAC с частотой равной частоте семплирования, которую вы прочитали в заголовке WAV файла.
Golikov A.
Цитата
Еще в DMA есть режим с двумя буферами, Double Buffer Mode, я использую его для воспроизведения или записи чего-либо.

это что за режим такой? как включить?
Quasar
Цитата(Golikov A. @ May 7 2015, 08:21) *
это что за режим такой? как включить?


Сорри, дезинформировал, у F103 нет такого режима, это я с F407/417 перепутал.
Golikov A.
А... только я не понял в чем бизнес. Ведь можно сделать буффер в 2 раза больше, и в циркулярном режиме будет тоже самое первая половина и вторая, или в случае дабл буффер у нас будет прерывание в середине и в конце каждого, то есть по 4 на круг, вместо 2 для обычного циркулярного режима?
loreal1970
В общем пару дней отдохнул и доделал чтение WAV.
Конечно было неправильное преобразование.
Еще сбило с толку, что WAV у меня был с данными signed.
Пока написано коряво (по быстрому), но работает.
Еще раз благодарю и с ПРАЗДНИКОМ 9 МАЯ!
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.