Игорь 2
Трансиверы, передатчики, РПУ => Software Defined Radio (SDR) => Тема начата: ra0ahc от Сентябрь 27, 2020, 07:19:51 pm
-
Провел несколько дней за экспериментом : Вывод звука через цап.
Так как больше у меня ничего нет, делаю фактически на голой плате.
Вот такой код написал по выводу то одного буфера то другого. Заполнение с сохранением фазы. Просто Синус пытаюсь вывести на ЦАП. Все работает в бесконечном цикле через DMA без участия процессора. Настроил DMA , ЦАП, таймер на 24кГц сэмплирование. Короче работает, но есть проблема. Она на фотке. Это момент переключения буфера.
void DMA1_Stream6_IRQHandler(void)
{
uint8_t old = dacTxBankNawNumber;
dacTxBankNawNumber= (uint8_t)(~dacTxBankNawNumber & 1);
HAL_DAC_Stop_DMA(&hdac,DAC_CHANNEL_2);
if (HAL_DAC_Start_DMA(&hdac, DAC_CHANNEL_2, (uint32_t *) &pOutDac[dacTxBankNawNumber][0], FRAME_SIZE,
DAC_ALIGN_12B_R) != HAL_OK) { Error_Handler(); }
float32_t delta = pp * 1500 / bit;
for (int i = 0; i < FRAME_SIZE; i++) {
pOutDac[old][i ] = (uint32_t) (100 + arm_sin_f32(phase) * 100);
phase += delta;
if (phase > pp) phase -= pp;
}
HAL_DMA_IRQHandler(&hdma_dac2);
}
-
Причем фаза действительно совпадает. Но вот этот скачок я не могу победить.
-
Прогресс !
-
Нашел причину. Достал Геннадия. Как всегда не документированные переменные в CubeMX
Теперь так
-
Из-за использования дешевой звуковухи , у нее только микрофонный вход, а у меня выход 3 вольта с цап (при 12БИТ). Так что пришлось снижать искусственно битность выхода (типа регулировка громкости)
-
Ну и пришлось переделывать стандартные процедуры HAL. Это связано с тем , что я не знаю как создавать CallBack функции.
Ну и листинг программы того , что на фотке.
Обработчик прерывания по окончанию передачи буфера. (заполнение синусом свободного буфера)
void DMA1_Stream6_IRQHandler(void)
{
/* USER CODE BEGIN DMA1_Stream6_IRQn 0 */
if ((DMA1->HISR & DMA_HISR_TCIF6) != 0) {
uint8_t b = (uint8_t) ((hdma_dac2.Instance->CR & DMA_SxCR_CT) != 0);
if (b != 0)
dacTxBankNawNumber = 0;
else
dacTxBankNawNumber = 1;
float32_t amp=550;
for (int i = 0; i < FRAME_SIZE ; i++) {
pOutDac[dacTxBankNawNumber][i ] = (uint32_t) (amp + arm_sin_f32(phase) * amp);
phase += delta;
if (phase > pp) phase -= pp;
pOutDac[dacTxBankNawNumber][i ] = (uint32_t) (amp + arm_sin_f32(phase) * amp) | pOutDac[dacTxBankNawNumber][i ]<<16 ;
phase += delta;
if (phase > pp) phase -= pp;
}
}
/* USER CODE END DMA1_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_dac2);
/* USER CODE BEGIN DMA1_Stream6_IRQn 1 */
/* USER CODE END DMA1_Stream6_IRQn 1 */
}
-
старт ДМА передачи на цап
__IO uint32_t pOutDac[2][FRAME_SIZE];
.
.
.
delta = (float32_t) (2 * 3.14159265359 * 740 / 24000);//740Hz
if (HAL_DAC_Start_DMA_DBM(&hdac, DAC_CHANNEL_2, (uint32_t *) &pOutDac[0][0], (uint32_t *) &pOutDac[1][0],FRAME_SIZE*2) != HAL_OK) {
Error_Handler();
}
-
///
HAL_StatusTypeDef HAL_DAC_Start_DMA_DBM(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t *pData, uint32_t *pData1, uint32_t Length) {
uint32_t tmpreg = 0U;
/* Check the parameters */
assert_param(IS_DAC_CHANNEL(Channel));
// assert_param(IS_DAC_ALIGN(Alignment));
/* Process locked */
__HAL_LOCK(hdac);
/* Change DAC state */
hdac->State = HAL_DAC_STATE_BUSY;
/* Set the DMA transfer complete callback for channel2 */
hdac->DMA_Handle2->XferCpltCallback = DAC_DMAConvCpltCh2;
/* Set the DMA half transfer complete callback for channel2 */
hdac->DMA_Handle2->XferHalfCpltCallback = DAC_DMAHalfConvCpltCh2;
/* Set the DMA error callback for channel2 */
hdac->DMA_Handle2->XferErrorCallback = DAC_DMAErrorCh2;
/* Enable the selected DAC channel2 DMA request */
hdac->Instance->CR |= DAC_CR_DMAEN2;
/* Case of use of channel 2 */
/* Get DHR12R2 address */
tmpreg = (uint32_t) &hdac->Instance->DHR12R2;
/* Enable the DAC DMA underrun interrupt */
__HAL_DAC_ENABLE_IT(hdac, DAC_IT_DMAUDR2);
/* Enable the DMA Stream */
HAL_DMAEx_MBStart_IT(hdac->DMA_Handle2, (uint32_t) pData, tmpreg, (uint32_t) pData1, Length);
/* Enable the Peripheral */
__HAL_DAC_ENABLE(hdac, Channel);
/* Process Unlocked */
__HAL_UNLOCK(hdac);
/* Return function status */
return HAL_OK;
}
HAL_StatusTypeDef HAL_DMAEx_MBStart_IT(DMA_HandleTypeDef *hdma, uint32_t SrcAddress, uint32_t DstAddress,
uint32_t SecondMemAddress, uint32_t DataLength) {
HAL_StatusTypeDef status = HAL_OK;
/* Check the parameters */
assert_param(IS_DMA_BUFFER_SIZE(DataLength));
/* Process locked */
__HAL_LOCK(hdma);
if (HAL_DMA_STATE_READY == hdma->State) {
/* Change DMA peripheral state */
hdma->State = HAL_DMA_STATE_BUSY;
/* Initialize the error code */
hdma->ErrorCode = HAL_DMA_ERROR_NONE;
/* Enable the Double buffer mode */
hdma->Instance->CR |= (uint32_t) DMA_SxCR_DBM;
/* Configure DMA Stream destination address */
hdma->Instance->M1AR = SecondMemAddress;
/* Configure the source, destination address and the data length */
//DMA_MultiBufferSetConfig(hdma, SrcAddress, DstAddress, DataLength);
hdma->Instance->NDTR = DataLength;
/* Peripheral to Memory */
/* Configure DMA Stream destination address */
hdma->Instance->PAR = DstAddress;
/* Configure DMA Stream source address */
hdma->Instance->M0AR = SrcAddress;
/* Clear all flags */
__HAL_DMA_CLEAR_FLAG (hdma, __HAL_DMA_GET_TC_FLAG_INDEX(hdma));
/* Enable Common interrupts*/
hdma->Instance->CR |= DMA_IT_TC;
/* Enable the peripheral */
__HAL_DMA_ENABLE(hdma);
} else {
/* Process unlocked */
__HAL_UNLOCK(hdma);
/* Return error status */
status = HAL_BUSY;
}
return status;
}
-
Хороший пример
http://www.lucadavidian.com/2017/11/17/stm32f4-using-the-dma-controller-with-adc/
-
Точность подбора частоты деления cr123 cr123 cr123
Должно быть 740Гц
-
lllol
-
Сейчас с цап идёт вот такой сигнал , поэтому палок там в сигнале полно. lllol
-
Походу ошибка в заполнении буфера . Не должно быть такой зебры.
-
Я так и думал, не правильно массив заполнил. Очень быстро перегружается вход. Вот более менее нормальный синус.
-
void DMA1_Stream6_IRQHandler(void) {
/* USER CODE BEGIN DMA1_Stream6_IRQn 0 */
if ((DMA1->HISR & DMA_HISR_TCIF6) != 0) {
uint8_t b = (uint8_t) ((hdma_dac2.Instance->CR & DMA_SxCR_CT) != 0);
if (b != 0)
dacTxBankNawNumber = 0;
else
dacTxBankNawNumber = 1;
float32_t amp = 100;
for (int i = 0; i < FRAME_SIZE; i++) {
pOutDac[dacTxBankNawNumber][i ] = (uint32_t) (amp + arm_sin_f32(phase) * amp);
phase += delta;
if (phase >= pp) phase -= pp;
pOutDac[dacTxBankNawNumber][i ] |= ((uint16_t) (amp + arm_sin_f32(phase) * amp)) << 16;
phase += delta;
if (phase >= pp) phase -= pp;
}
}
/* USER CODE END DMA1_Stream6_IRQn 0 */
HAL_DMA_IRQHandler(&hdma_dac2);
/* USER CODE BEGIN DMA1_Stream6_IRQn 1 */
/* USER CODE END DMA1_Stream6_IRQn 1 */
}
-
на словах не объясните как победили скачек в синусоиде в момент переключения буфера ?
-
Там по простому не тот размер буфера был. Синус строился нормально
-
Все не очевидно. Hal просит два буфера по uint32 , и просит длину буфера. В этом и вопрос оказался. Какую длину буфера ставить? Вот я нормальный программер поставил длину буфера как есть 1024. Как потом выяснилось , что hal отправляет через дма пол слова! Что впринципе разумно цап всего 12 бит и смысла отправлять 32 бита нет. Вот и пришлось длину для hal ставить в два раза длиннее, так как он хочет количество отправок по пол слова 16 бит.
Ну и заполнение буфера нужно было делать в uint32 два значения амплитуды для цап по 16 бит.
Короче : при работе с Hal там где он просит длину - нужно ставить количество отправок.