Полная версия этой страницы:
STM32F407 + CS43L22
Есть многим знакомая платка STM32F4DISCOVERY.
На ней есть I2S DAC CS43L22
Так вот выяснилось, что I2S модуль контроллера STM32F407 не может корректно работать с этим кодеком !!!
Причина оказалась в том, что сигнал MCK у микроконтроллера начинает тикать только в момент передачи аудио выборок, то есть одновременно вместе с сигналами SCK, SD и WS !!!
Отдельно запустить MCK в режиме free running нельзя !!!
Но, в даташите на кодек CS43L22 явно указано, что частота MCK должна включаться заранее, а именно в момент инициализации, а отключаться только через опр. время после завершения передачи аудио данных!!!
Оно конечно работает, звук играет и все такое, но я столкнулся со след проблемами которые не могу решить:
1) При воспроизведении самого первого аудио файла пропадает почти пол секунды из его начала !!!
(я это связываю с тем, что так как частота MCK включается одновременно с поступлением данных, то кодек CS43L22 не сразу настраивается на эту частоту)
2) При окончании проигрывания слышен белый шум, на довольно сильной громкости, причем в одном канале громкость его существенно больше. (замечу что при проигрывании файла громкость одинаковая в обоих каналах).
Этот шум не устраняется даже подачей команд MUTE, или уменьшением громкости, помогает только сброс ресетом и последующая переинициализация, что меня не устраивает !!!
Возникает вопрос, о чем думали разработчики когда ставили этот кодек на отладочную плату?
Я начал делать проект на этой плате мне нужен и микрофон и наушники. Но мне в первую очередь надо запустить USB HOST.
Раньше я работал с кодеками AD73322 и SSM2603.
Там уходило много времени после инициализации на заряд конденсатора с опорным напряжением.
1) В AD73322 и SSM2603 я намеренно отключаю подачу MCLK для экономии энергии и эффекта как у вас при включении не наблюдаю. Я еще не изучил CS43L22 но вижу на блок схеме charg pump. Возможно у вас нет звука именно пока заряжается кондер после инициализации. Свои кодеки я инициализирую сразу после подачи питания и больше этого не делаю.
2) На шине I2S при этом уже нет никаких данных?
Цитата(uriy @ Jan 9 2017, 18:10)

Я начал делать проект на этой плате мне нужен и микрофон и наушники. Но мне в первую очередь надо запустить USB HOST.
Раньше я работал с кодеками AD73322 и SSM2603.
Там уходило много времени после инициализации на заряд конденсатора с опорным напряжением.
1) В AD73322 и SSM2603 я намеренно отключаю подачу MCLK для экономии энергии и эффекта как у вас при включении не наблюдаю. Я еще не изучил CS43L22 но вижу на блок схеме charg pump. Возможно у вас нет звука именно пока заряжается кондер после инициализации. Свои кодеки я инициализирую сразу после подачи питания и больше этого не делаю.
2) На шине I2S при этом уже нет никаких данных?
По первому пункту у меня пауза 250 мкс после иициализации, да еще я и отладчиком в этом месте останавливался, так что он бы успел зарядиться.
Там в инициализации есть регистр тактироввания, там есть бит AUTO, он позволяет не указывать частоту MCK которая будет на него подана, а автоматически ее определять. Так вот у меня этот бит установлен, а так как частота появляется одновременно с данными, а не заранее, то видимо это время как раз тратится на это автоопределение частоты MCK
А по второму пункту данных точно никаких нет, DMA выключен, блок I2S выключен.
Там кстати есть еще аналоговый микшер, так вот я его тоже выключаю при инициализации.
p/s микрофон у меня тоже задействован, но с ним проблем не возникло )
Цитата
Once MCLK is valid, the quiescent voltage, VQ, and the internal voltage reference, FILT+, will begin powering
up to normal operation. The charge pump slowly powers up and charges the capacitors. Power is then
applied to the headphone amplifiers and switched-capacitor filters, and the analog/digital outputs enter a muted
state. Once LRCK is valid, MCLK occurrences are counted over one LRCK period to determine the
MCLK/LRCK frequency ratio and normal operation begins.
Как я это понимаю. После подачи MCLK медленно заражаются кондеры в charge pump (время нигде не нашел). После этого аудивыходы переходят в muted. И только теперь анализируется частота MCLK и вероятно бит AUTO. Очень странное для меня поведение MCLK.
В SSM2603 уходит около 100 мсек(!) на заряд кондера емкостью 10 мкФ.
Цитата
А по второму пункту данных точно никаких нет, DMA выключен, блок I2S выключен.
А осцилом посмотреть?
Как насчет таких вариантов:
1. Всегда гнать данные через I2S чтобы не пропадал сигнал MCLK.
2. Вместо MCLK задействовать выход таймера. На этом пине есть TIM8 и TIM3
Цитата(uriy @ Jan 9 2017, 20:05)

А осцилом посмотреть?
Я осциллом тоже смотрел.
Попробую подать с таймера, посмотрю что изменится.
Но у меня нет там таких емкостей, 1мкф максимум, да и полсекунды многовато на это.
сегодня попробую, завтра напишу что получилось)
Завел я частоту MCK с таймера, и как и ожидалось, сразу исчезла проблема пропадания начала проигрывания, и
и при окончании проигрывания шумы тоже исчезли !!!!
НО, так как частоты MCK, SCK, LRCK должны биться, а у меня МСК идет от отдельного таймера, а SCK и LRCK от модуля I2S,
то звук получился как из ж..ы!
Я предполагал что так будет, но зато проверил что действительно MCK надо подавать заранее а
отключать с задержкой после окончания проигрывания!
Теперь вот думаю что надо переводить кодек в режим мастера, а микроконтроллер будет слэйвом,
тогда кодек сам будет нарезать сигналы SCK и LRCK, правда выбор делителей MCK там какой-то мутный,
возможно и не получится.
Цитата
НО, так как частоты MCK, SCK, LRCK должны биться
Откуда это следует? SCK и LRCK да будут синхронны. MCLK в упомянутом мною кодеке SSM2603 вовсе может поступать от кварцевого резонатора подключенного прямо к кодеку. Не думаю что нужна синхронная MCLK.
Частота сэмплирования определяется сигналом LRCK.
Цитата
Я предполагал что так будет
Не вижу в этом логики.
1. Какую частоту MCLK вы сделали?
2. На MCLK меандр с 50% заполнением?
Цитата
Теперь вот думаю что надо переводить кодек в режим мастера
Я именно так и делаю. В хост контроллере включаю прерывания по приему данных через I2S и в этом же прерывании отправляю данные в кодек.
Цитата
правда выбор делителей MCK там какой-то мутный,
Вроде в
Table 1. Serial Port Clocking все понятно.
MCK у меня 2048 Кгц (это когда I2S генерит)
Шим 50%, c таймера удалось сделать только 2048780 (84000000/41)
Тем не менее звук испорчен (очень хриплый что ли стал)
Поэтому и решил что частоты должны биться.
MCK не важно, это когда кодек мастер и сам генерит CK и RLCK, а у меня то слейв.
А в таблице напрягает что нет RATIO=32 для СK и RLCK, а только 64.
А у меня сейчас частота CK=256Кгц, а RLCK=8 Кгц так как данные у меня по 16 бит передаются для каждого канала
Разве такая низкая частота для MCLK допустима?
Минимальное что я вижу в таблицах для настройки регистров это 6.1440 МГц.
Также в даташите написано 7. Optimal PWM performance is achieved when MCLK > 12 MHz
Сделайте 12МГц
Цитата(uriy @ Jan 10 2017, 17:42)

Разве такая низкая частота для MCLK допустима?
Минимальное что я вижу в таблицах для настройки регистров это 6.1440 МГц.
Также в даташите написано 7. Optimal PWM performance is achieved when MCLK > 12 MHz
Сделайте 12МГц
Выходит допустима, раз работает )
Во всяком случае модуль i2s микроконтроллера умеет выводить только частоту Fs*256, а Fs у меня 8 КГц
Вот мастером сделаю кодек, тогда попробую 12Мгц
Как работает? Вы же сами сказали что звук как из ж.
Эта частота должна использоваться в сигма-дельта модуляторе. Возможно из-за этого искажения звука.
Просто поменяйте делитель таймера чтобы получить другую частоту на выходе и проверьте.
Цитата(uriy @ Jan 11 2017, 14:58)

Как работает? Вы же сами сказали что звук как из ж.
Эта частота должна использоваться в сигма-дельта модуляторе. Возможно из-за этого искажения звука.
Просто поменяйте делитель таймера чтобы получить другую частоту на выходе и проверьте.
Не, звук качественный когда все частоты генерит модуль i2s, а когда MCK я сам генерю таймером (это чтоб его заранее включать, чтобы начало файла не проглатывалось)
то тогда звук уже искаженный, но файл теперь сначала воспроизводит
Перевел вчера кодек в режим MASTER, а микроконтроллер в SLAVE.
Задал частоту MCK микроконтроллера 12.28 МГц через выход MCO2 (поигрался с настройкой PLL)
В итоге с кодека получил частоту LRCK равную 8KHz и частоту SCK равную 512KHz
Таким образом получил RATIO (SCK/LRCK)=64, но для этого надо передавать на кодек данные по 32 бита а не по 16,
поэтому переключил i2s модуль микроконтроллера в режим << LSB justified 16-bit extended to 32-bit packet frame with CPOL = 0 >>
а кодек переключил в режим Right-Justified Format и биты AWL поставил в единицы (Audio word length=16 bit)
В итоге звук стал нормальный, но опять сьелся начальный кусочек файла ). Но наверное это уже с DMA проблема, так как теперь постоянно присутствует клок SCK.
Все победил я этот кодек, звук нормальный, файлик проигрывает полностью.
Конечно в том виде как это было сделано в примере audio playback and record от MCD Application Team это было неработоспособно
Около полугода назад пробовал думаю этот пример. Запись на флешку с микрофона а потом воспроизведение.
У меня все отлично работало.
работало, потому что в примере по умолчанию стоит работа через ЦАП микроконтроллера, а выход цапа подкл. к аналоговому входу кодека.
Неожиданный поворот, не знал.
Цитата(kumle @ Jan 13 2017, 11:45)

работало, потому что в примере по умолчанию стоит работа через ЦАП микроконтроллера, а выход цапа подкл. к аналоговому входу кодека.
не, сейчас глянул, по умолчанию всетаки через i2S
но все равно, даже если и так, все равно работало неправильно, так как начальный кусок файла глотает из-за того что MCK заранее не включается
и выключается тоже некорректно из-за того что MCK должен некоторое время тикать после проигрывания.
Вобщем я обе эти проблемы устранил
Dmitry2017
Sep 24 2017, 13:25
У меня аналогичная проблема. При работе с I2S как мастер, а кодека как слейв после воспроизведения сэмпла иногда включаются шумы.
Вот инициализация шин:
CODE
// configure I2S port
SPI_I2S_DeInit(CODEC_I2S);
I2S_InitType.I2S_AudioFreq = I2S_AudioFreq_22k;
I2S_InitType.I2S_MCLKOutput = I2S_MCLKOutput_Enable;
//I2S_InitType.I2S_MCLKOutput = I2S_MCLKOutput_Disable;
I2S_InitType.I2S_DataFormat = I2S_DataFormat_16b;
I2S_InitType.I2S_Mode = I2S_Mode_MasterTx;
//I2S_InitType.I2S_Mode = I2S_Mode_SlaveTx;
I2S_InitType.I2S_Standard = I2S_Standard_Phillips;
I2S_InitType.I2S_CPOL = I2S_CPOL_Low;
I2S_Init(CODEC_I2S, &I2S_InitType);
I2S_Cmd(CODEC_I2S, ENABLE);
// configure I2C port
I2C_DeInit(CODEC_I2C);
I2C_InitType.I2C_ClockSpeed = 100000;
I2C_InitType.I2C_Mode = I2C_Mode_I2C;
I2C_InitType.I2C_OwnAddress1 = CORE_I2C_ADDRESS;
I2C_InitType.I2C_Ack = I2C_Ack_Enable;
I2C_InitType.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_InitType.I2C_DutyCycle = I2C_DutyCycle_2;
Вот конфигурация кодека:
CODE
void codec_ctrl_init()
{
uint32_t delaycount;
uint8_t CodecCommandBuffer[3];
uint8_t regValue = 0xFF;
GPIO_SetBits(GPIOD, CODEC_RESET_PIN);
delaycount = 1000000;
while (delaycount > 0)
{
delaycount--;
}
//keep codec OFF
CodecCommandBuffer[0] = CODEC_MAP_PLAYBACK_CTRL1;
CodecCommandBuffer[1] = 0x01;
send_codec_ctrl(CodecCommandBuffer, 2);
//begin initialization sequence (p. 32)
CodecCommandBuffer[0] = 0x00;
CodecCommandBuffer[1] = 0x99;
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = 0x47;
CodecCommandBuffer[1] = 0x80;
send_codec_ctrl(CodecCommandBuffer, 2);
regValue = read_codec_register(0x32);
CodecCommandBuffer[0] = 0x32;
CodecCommandBuffer[1] = regValue | 0x80;
send_codec_ctrl(CodecCommandBuffer, 2);
regValue = read_codec_register(0x32);
CodecCommandBuffer[0] = 0x32;
CodecCommandBuffer[1] = regValue & (~0x80);
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = 0x00;
CodecCommandBuffer[1] = 0x00;
send_codec_ctrl(CodecCommandBuffer, 2);
//end of initialization sequence
CodecCommandBuffer[0] = CODEC_MAP_PWR_CTRL2;
CodecCommandBuffer[1] = AUTO;
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = CODEC_MAP_PLAYBACK_CTRL1;
CodecCommandBuffer[1] = 0x70;
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = CODEC_MAP_CLK_CTRL;
CodecCommandBuffer[1] = 0x81; //auto detect clock
//CodecCommandBuffer[1] = 0x60; //speed 1:1
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = CODEC_MAP_IF_CTRL1;
//CodecCommandBuffer[1] = CODEC_STD;
CodecCommandBuffer[1] = 0x07;
//CodecCommandBuffer[1] = 0x84; //Master
send_codec_ctrl(CodecCommandBuffer, 2);
CodecCommandBuffer[0] = CODEC_MAP_PWR_CTRL1;
CodecCommandBuffer[1] = 0x9E;
send_codec_ctrl(CodecCommandBuffer, 2);
}
Сами данные я отправляю через ДМА I2S (SPI3)
Я пытался повторить Ваш опыт установив кодек в мастер и дергая MCLK таймером. Пока безрезультатно.
Расскажите пожалуйста подробнее про настройку I2S, MCLK и таймера. Как вы добились частоты 12.2880 MHz?
У меня частота проца 84 МГц и если перскаллер установить в 0, а период поставить на 3, у меня зависает инициализация таймера
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.