Форум Радиолюбителей

DAC (ЦАП) stm32f429 Лаба

24524 просмотров, 18 ответов

ra0ahc 27 сентября 2020 г. в 07:19#1
Провел несколько дней за экспериментом : Вывод звука через цап.
Так как больше у меня ничего нет, делаю фактически на голой плате.

Вот такой код написал по выводу то одного буфера то другого. Заполнение с сохранением фазы. Просто Синус пытаюсь вывести на ЦАП. Все работает в бесконечном цикле через 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);
}
ra0ahc 27 сентября 2020 г. в 07:20#2
Причем фаза действительно совпадает. Но вот этот скачок я не могу победить.
ra0ahc 1 октября 2020 г. в 05:15#3
Прогресс !
ra0ahc 1 октября 2020 г. в 05:16#4
Нашел причину. Достал Геннадия. Как всегда не документированные переменные в CubeMX
Теперь так
ra0ahc 1 октября 2020 г. в 05:19#5
Из-за использования дешевой звуковухи , у нее только микрофонный вход, а у меня выход 3 вольта с цап (при 12БИТ). Так что пришлось снижать искусственно битность выхода (типа регулировка громкости)
ra0ahc 1 октября 2020 г. в 05:24#6
Ну и пришлось переделывать стандартные процедуры 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 */
}
ra0ahc 1 октября 2020 г. в 05:26#7
старт ДМА передачи на цап

__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();
}

ra0ahc 1 октября 2020 г. в 05:26#8
///

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;
}

ra0ahc 1 октября 2020 г. в 05:30#9
ra0ahc 1 октября 2020 г. в 05:31#10
Точность подбора частоты деления
Должно быть 740Гц
ra0ahc 1 октября 2020 г. в 05:35#11
ra0ahc 1 октября 2020 г. в 05:41#12
Сейчас с цап идёт вот такой сигнал , поэтому палок там в сигнале полно.
ra0ahc 1 октября 2020 г. в 06:00#13
Походу ошибка в заполнении буфера . Не должно быть такой зебры.
ra0ahc 1 октября 2020 г. в 08:09#14
Я так и думал, не правильно массив заполнил. Очень быстро перегружается вход. Вот более менее нормальный синус.
ra0ahc 1 октября 2020 г. в 08:10#15
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 */
}
VA7KL 1 октября 2020 г. в 08:47#16
на словах не объясните как победили скачек в синусоиде в момент переключения буфера ?
GenaSPB 1 октября 2020 г. в 09:34#17
Там по простому не тот размер буфера был. Синус строился нормально
ra0ahc 2 октября 2020 г. в 08:37#18
Все не очевидно. Hal просит два буфера по uint32 , и просит длину буфера. В этом и вопрос оказался. Какую длину буфера ставить? Вот я нормальный программер поставил длину буфера как есть 1024. Как потом выяснилось , что hal отправляет через дма пол слова! Что впринципе разумно цап всего 12 бит и смысла отправлять 32 бита нет. Вот и пришлось длину для hal ставить в два раза длиннее, так как он хочет количество отправок по пол слова 16 бит.
Ну и заполнение буфера нужно было делать в uint32 два значения амплитуды для цап по 16 бит.
Короче : при работе с Hal там где он просит длину - нужно ставить количество отправок.