Игорь 2
Трансиверы, передатчики, РПУ => Software Defined Radio (SDR) => Тема начата: ra0ahc от Сентябрь 20, 2020, 07:34:03 pm
-
SAI протокол (Serial Audio Interface)
Это навороченный i2s
В моем процессоре он есть. И его надо стартануть.
У меня есть проблема в понимании.
Вот настройки sai в CubeMX
И формат данный и формат слота.
-
Идет поток данных (пока один канал) но квадратура (в левый и правый каналы) так считать размер одного замера =32 бита , то есть фактически амплитуды 32битного АЦП (для простоты понимания). Поток непрерывный.
Что такое FRAME LENGTH? (это вопрос) Он должен совпадать с дампом памяти который я выделил в процессоре, точнее не так...это минимальная длина массива в процессоре, которое должно быть выделено? либо кратно этой цифре.
В Кубе там размер стоит (FRAME LENGTH )от 8 ло 256 бит или от 256 байт и выше за один сэмпл.
Если брать 48000Гц поток то это 20мкСек на один сэмпл. У меня в одной банке 1024 сэмплов ...итого около 20мСек на один прием. За 20мСек нужно посчитать смеситель, АРУ, ФИР фильтр, там еще что-то. Круто блин.
Я запутался в трех соснах. Какой длины должна быть передача(FRAME LENGTH)? И это стерео?
-
Разобрался.
Все очень просто и логично.
В данном процессоре 8 каналов для звука, можно по SAI гнать. Это 4 канала на левый и 4 канала на правый (слотов). И если размерность амплитуды 32бита, то как раз на общих 8 слотов будет в длину 256 бит или 32 байта за одно передачу. И это все в бесконечном потоке.
Или у меня: 32+32 бита квадратура =64бита FRAME LENGTH.
Или ДМА скушает 8байт за один прием. за 20мкСек. длина буфера получается при 1024 замеров ацп =8192байта.
-
Пока не могу стартануть на передачу...
-
HAL_NVIC_EnableIRQ(DMA2_Stream1_IRQn);
HAL_NVIC_SetPriority(DMA2_Stream1_IRQn, 0, 0);
HAL_SAI_TxCpltCallback(&hsai_BlockA1);
__HAL_SAI_ENABLE(&hsai_BlockA1);
HAL_SAI_IRQHandler(&hsai_BlockA1);
if (HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *) saiTxBank, 4 * FRAME_SIZE) != HAL_OK) Error_Handler();
Хрен его знает как ТХ запустить через ДМА и чтоб еще прерывание сработало об окончанию.
-
Если тактовые сигналы на соответствующий канал а или б приходят, он начнет запрвшивать у dma. Еажется там был бит в слове состояния, который состояние ws показывал? Или то у spi/i2s было... не помню.
-
Прервания от sai при нормальной работе вам и не потребуются.
-
Предполагаю что не приходят. На ws и bclk есть сигналы?
-
Хоть один активный слот в конфигурации стоит?
-
Я пытаюсь передать блок в воздух. Не один провод не подключен.
ПЕрвая передача проходит (вроде, нечем смотреть)
if (hsai_BlockA1.State == HAL_SAI_STATE_READY)
if (HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *) saiTxBank, 4*FRAME_SIZE) != HAL_OK) Error_Handler();
и после выполнения - тишина, ни прерывание ни callback не срабатывают.
проверяю состояние =HAL_SAI_STATE_BUSY_TX постоянно.
Может в воздух нельзя передавать?
-
Вот настройки saiA и DMA
-
SAI TX - нет cr123
перед вызовом функции ТХ hsai_BlockA1.State=READY дает....ну готов значит sai к TX
Дальше:
if (HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *) saiTxBank, 4 ) != HAL_OK) Error_Handler();
дает HAL_OK. Значит функция работает корректно.
HAL_StatusTypeDef HAL_SAI_Transmit_DMA(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size)
{
if((pData == NULL) || (Size == 0))
{
return HAL_ERROR;
}
if(hsai->State == HAL_SAI_STATE_READY)
{
/* Process Locked */
__HAL_LOCK(hsai);
hsai->pBuffPtr = pData;
hsai->XferSize = Size;
hsai->XferCount = Size;
hsai->ErrorCode = HAL_SAI_ERROR_NONE;
hsai->State = HAL_SAI_STATE_BUSY_TX;
/* Set the SAI Tx DMA Half transfer complete callback */
hsai->hdmatx->XferHalfCpltCallback = SAI_DMATxHalfCplt;
/* Set the SAI TxDMA transfer complete callback */
hsai->hdmatx->XferCpltCallback = SAI_DMATxCplt;
/* Set the DMA error callback */
hsai->hdmatx->XferErrorCallback = SAI_DMAError;
/* Set the DMA Tx abort callback */
hsai->hdmatx->XferAbortCallback = NULL;
/* Enable the Tx DMA Stream */
if(HAL_DMA_Start_IT(hsai->hdmatx, (uint32_t)hsai->pBuffPtr, (uint32_t)&hsai->Instance->DR, hsai->XferSize) != HAL_OK)
{
__HAL_UNLOCK(hsai);
return HAL_ERROR;
}
/* Check if the SAI is already enabled */
if((hsai->Instance->CR1 & SAI_xCR1_SAIEN) == RESET)
{
/* Enable SAI peripheral */
__HAL_SAI_ENABLE(hsai);
}
/* Enable the interrupts for error handling */
__HAL_SAI_ENABLE_IT(hsai, SAI_InterruptFlag(hsai, SAI_MODE_DMA));
/* Enable SAI Tx DMA Request */
hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
/* Process Unlocked */
__HAL_UNLOCK(hsai);
return HAL_OK;
}
else
{
return HAL_BUSY;
}
}
самая основная функция "красная" и она тоже дает = HAL_OK.
-
Но после выполнения HAL_SAI_Transmit_DMA, статус становится hsai_BlockA1.State =BUSY
И так и остается в таком положении...
-
И HAL_SAI_Transmit просто даже эта команда вылетает с ошибкой по таймауту , без всяких ДМА.
Я явно делаю что-то не то. no88
-
HAL_SAI_Transmit_DMA
Работает, исправил настройки слотов.
С приемом номер не прошел.
Хочу через А канал передавать, по каналу В принимать. ВСе синхро выводы у них соединены, только ДАТА надо кинуть проводком (которого нет)
Настройки канала А (ТХ)
-
Вот так работает!
Оказывается, пофиг что ссылка на массив (uint8_t *) , длина все-равно должна быть как (uint32_t) , хотя по логике должно быть FRAME_SIZE*4
HAL_SAI_Receive_DMA(&hsai_BlockB1, (uint8_t *) saiRxBank, FRAME_SIZE)
HAL_SAI_Transmit_DMA(&hsai_BlockA1, (uint8_t *) saiTxBank, FRAME_SIZE)
-
Передача с канала А в канал В 2кб
И прием тут же этих 2 кб в память, вообще практически не повлияло на скорость. Все взял ДМА на себя. То есть процессор практически не участвует в этом процессе.
Но это еще без FIR и АРУ и тд.
-
Все надо переделывать. no88
Надо чтобы не было разрывов в приеме и передачи. Так же как в ЦАП с Помощью Геннадия мы сделали.
-
Пришлось все переделать.
Теперь так:
1.формирую сигнал в двух буферах последовательно с соблюдением фазы. Пока один буфер передается с помощь ДМА я заполняю втрой, потом меняюсь местами.
2.Передаю через SAI интерфейс блоки по 32бита (1 слот, со свободным протоколом).
3. Принимаю опять с помощью ДМА в два буфера по очереди.
4. После приема очередного буфера, обрабатываю его (3кГц FIR фильтр) и отправляю в свободный буфер ЦАП (тоже работает по системе 2 буферов).
5. ДМА отправляет по очереди буфер в ЦАП на выходе которого получается вот такой синал.
-
Из-за особенностей деления и умножения 8МГц кварца в процессоре получается ошибка. Должна быть палка на 1000Гц. Это связано с формированием тактового сигнала для SAI
-
Проблема была в синхронизации выхода на ЦАП и входа с SAI они упорно не сихронизировались. Максимум через 1 минуту происходила разсинхроницация и потеря одного блока. Звучит это в наушниках мерзко.
На фотке как раз момент разсинхронизации.
После долгих танцев с бубном я смог повесить внешнею синхронизацию на выход ЦАП. Теперь всё синхронизируется от выхода CLK SAI интерфейса.
-
Теперь сами настройки в CubeMX
настройки SAI
Да, и еще, там маркировка выходов попутана, либо у меня в голове бардак.
-
Теперь настройка DAC
кинут проводок физически между контактами. PG9 PE4 это как раз CLK от SAI
-
Теперь нафига всё так сложно. 123123
Да просто процессор практически свободен от пересылок. Максимум он сейчас формирует бесконечную синусоиду, фильтрует фир фильтром и копирует буфер в буфер ЦАП. Т.е. все работает на прерываниях и как бы не был процессор занят он всегда будет сперва заниматься прерываниями (звуком) и только потом основным потоком программы. Основной поток может зависнуть, а звук всеравно будет ))
В это время основной процесс процессора считает ФФТ и выводит на экран панораму и водопад. И он их выводит на максимально возможной скорости (зависит только от прихода данных).
-
Важный момент!
Сперва стартуем ЦАП потом SAi
//start DAC
if (HAL_DAC_Start_DMA_DBM(&hdac, DAC_CHANNEL_2, (uint32_t *) &pOutDac[0][0], (uint32_t *) &pOutDac[1][0],
FRAME_SIZE) != HAL_OK) {
Error_Handler();
}
HAL_Delay(1000);
//sai start
if (HAL_SAI_Transmit_DMA_DBM(&hsai_BlockA1, (uint8_t *) &saiTxBank[0][0], (uint8_t *) &saiTxBank[1][0],
FRAME_SIZE) != HAL_OK) {
Error_Handler();
}
if (HAL_SAI_Receive_DMA_DBM(&hsai_BlockB1, (uint8_t *) &saiRxBank[0][0], (uint8_t *) &saiRxBank[1][0],
FRAME_SIZE) != HAL_OK) {
Error_Handler();
}
-
Итоговое фото
-
Я не слежу особо за темой, а правильно я понимаю, что плата STM сейчас у Вас управляет какой-то штукой, на которой Вы, собственно, и делаете устройство обработки? cr123
-
Неа, это просто плата, я в ней смоделировал фактически всю цифровую, часть которая обычно идет с ПЛИС. Единственное, что я не могу смоделировать это полную работу двух приемников и панорамы, просто не хватает 256кБ памяти для реализации. Нужно 1мБ +++
Длина данных 2 приемника(I&Q) и панорамы (один сэмпл * 1024) 4*8*1024=32768 байт !!! и таких блоком нужно 8 шт в памяти. Поэтому могу только один приемник (I&Q) смоделировать это 4*2*1024 =8192 байт их вроде могу разместить в памяти. Просто в программ там целая куча блоков по 8 кб
Вот пример сколько массивов создается при старте. И это еще не все. Еще нужны блоки для АРУ и расчета FIR фильтра налету с учетом эквалайзера.
FRAME_SIZE=1024
float32_t - это 4 байта.
__IO float32_t p[FRAME_SIZE * 2];
__IO float32_t arr[FRAME_SIZE * 2];
__IO float32_t pFirOut[FRAME_SIZE];
__IO float32_t pOut[FRAME_SIZE];
__IO uint16_t pOutOld[FRAME_SIZE];
__IO uint32_t pOutDac[2][FRAME_SIZE];
__IO float32_t arrDac[FRAME_SIZE];
__IO float32_t firOutDac[FRAME_SIZE];
__IO float32_t win[FRAME_SIZE];
__IO float32_t pMag[FRAME_SIZE];
float32_t saiRxBank[2][FRAME_SIZE];
float32_t saiTxBank[2][FRAME_SIZE];
float32_t firStateF32[FRAME_SIZE + SAMPLEFILTER_TAP_NUM - 1];
float32_t firStateF32dac[FRAME_SIZE + SAMPLEFILTER_TAP_NUM - 1];
float32_t firStateF32sai[FRAME_SIZE + SAMPLEFILTER_TAP_NUM - 1];
-
не хватает 256кБ памяти для реализации. Нужно 1мБ +++
А 2 Мб STM32H747 хватит? Я правда SAI не развел, только АЦП и ЦАПы, и ДДС.
Вы Демо-board используете?
-
Хватит однозначно, но без sai не передать панораму с плис. Там у меня есть возможность передать сразу 8 слотов , на 7 ке там вроде больше да и самих каналов там 4 шт у меня 2 всего.
Тема оказалась более чем интересная.
-
Подождите , я про озу , а не про пзу
-
Да, это та самая платка Дискавери, всё одном. Там встроен 2д ускоритель и вся графика летает.
-
я про озу , а не про пзу
STM32F429ZIT6 microcontroller featuring 2 Mbytes of Flash memory, 256 Kbytes of RAM
STM32H747XIH6 microcontroller with 2 Mbytes of Flash memory and 1 Mbyte of RAM, SAI audio codec - Значит хватит? Что можно на его Дискавери-board сделать, я игрался с его двухядерностью.
без sai не передать панораму с плис
какую полосу панорамы вы рассчитываете показывать на вашей Дискавери-board?
-
какую полосу панорамы вы рассчитываете показывать на вашей Дискавери-board?
Константин, там технология такая, что это не имеет значения, любую можно. Всё зависит от возможностей проца. ВАшего с головой вплоть до 2048 точек хватит, лишь бы памяти хватило. 1мб это всего в 4 раза больше чем 256кб. Для сравнения, Геннадий в последнюю плату поставил 256мб за 100рублей.
Это не моя идея. Если Геннадий позволит ее здесь опубликовать, то я с удовольствием пожую. Пока всё, что здесь я делаю, я делал по векторам (идеологии процессов) от Геннадия Завидовского. Глобальное отличие подходов: Геннадий настройку проца ведет вручную, я с помощью CubeMX и HAL библиотеки. Хотя, последние настройки SAI DAC я фактически запускал вручную, правил HAL процедуры (про технологию двойного буфера для ДМА. В СubeMX она не описана, бля).
PS. Кстати от этой памяти отрежится память для монитора * 2
-
Велик соблазн: полностью собранная плата с видео STM32H747I-DISCO за $97... только мозги ей вправить (себе бы не повредить) и готова панорама к Монстру. ПЛИС для этого не нужно, так ведь? то для DDC.
Я перепаивал H747 Evaluation board под cpu clock 480 MHz - работает, быстро фракталы перерисовывает в тестах.
-
и готова панорама к Монстру. ПЛИС для этого не нужно, так ведь? то для DDC.
только наоборот ))) Монстр к панораме. Вся сильносигналка с фильтрами и каскадами и синтезатором и выход этой пч (16МГц) идет на ЦАП и ПЛИС.
ну или как я делал уже - две пч далее НЧ ДСП.
-
Вы кстате у Давида можете его платку купить ацп+плис и к ней свой проц и ПО подставить .
-
У всех DDC технологий узкое место -это чуйка или перегруз ацп.
Вот поэтому и надо сильносигналку с АРУ по пч. так сделано в фт101дх