Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM32F4 DAC+DMA Normal mode
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Sprite
Добрый день всем участникам форума!

Есть задача: выводить на ЦАП массив из 32-х значений данных в произвольное время (скажем в цикле или по нажатию кнопки). ЦАП настраивается на Normal mode, т.е. по задумке он должен один раз отработать массив данных и выключиться. Проблема в том, что данные выводятся только один (первый) раз при инициализации. Делаю так:
Код
//======================================================================
    __HAL_RCC_DMA1_CLK_ENABLE();
    __HAL_RCC_TIM4_CLK_ENABLE();
    __HAL_RCC_DAC_CLK_ENABLE();
    
    
    TIM4->PSC = 0;                                    //Предделитель
    TIM4->ARR = 83;                                    //Максимальное значение счетного регистра
    TIM4->CR2 = 0x0020;                                //MMS = Update
    TIM4->CR1 |= TIM_CR1_CEN;                        //Включаем таймер
    
    
    GPIO_InitStruct.Pin = GPIO_PIN_4;
    GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
    DAC->CR |= DAC_CR_DMAEN1;                        //разрешить прием данных канала №1 от ДМА
    DAC->CR |= DAC_CR_TSEL1_0|DAC_CR_TSEL1_2;        //Timer 4 TRGO event
    DAC->CR |= DAC_CR_TEN1;
    DAC->CR |= DAC_CR_EN1;                            //включить канал 1


    DMA1_Stream5->PAR = (uint32_t)&DAC1->DHR12R1;
    DMA1_Stream5->M0AR = (uint32_t)&Wave1[0];
    DMA1_Stream5->NDTR = 32;
    
    DMA1_Stream5->CR|= DMA_SxCR_CHSEL_0|DMA_SxCR_CHSEL_1|DMA_SxCR_CHSEL_2;    //DMA chanel 7 (согласно таблице "DMA1 request mapping" RM)
    DMA1_Stream5->CR|= DMA_SxCR_MSIZE_0;            //Memory data size = Half-word (16 bit)
    DMA1_Stream5->CR|= DMA_SxCR_PSIZE_0;            //Peripheral data size = Half-word (16 bit)
    DMA1_Stream5->CR|= DMA_SxCR_MINC;                //Memory address pointer is incremented after each data transfer
    //DMA1_Stream5->CR|= DMA_SxCR_CIRC;                //Circular mode
    DMA1_Stream5->CR|= DMA_SxCR_DIR_0;                //Направление 01: Memory-to-peripheral
    
    
    DMA1_Stream5->CR|= DMA_SxCR_EN;                    //Enable DMA
    
//======================================================================


И далее в программе так:
Код
    while (1)
    {
        HAL_Delay(1000);
      
        DMA1_Stream5->CR&= ~DMA_SxCR_EN;            //Disable DMA
        DMA1_Stream5->NDTR = 32;
        DMA1_Stream5->CR|= DMA_SxCR_EN;                //Enable DMA
    }


После первой инициализации данные выводятся, в цикле - не работает( Подозреваю, что не сбрасываю какой-то флаг.
Заранее спасибо!
adnega
Цитата(Sprite @ Mar 18 2018, 15:56) *
Подозреваю, что не сбрасываю какой-то флаг.

Да, неплохо бы перед инициализацией сбрасывать статус DMA, типа
Цитата
DMA2->LIFCR = (1 << DMA_LISR_HTIF0);
jcxz
Цитата(Sprite @ Mar 18 2018, 14:56) *
DMA1_Stream5->CR|= DMA_SxCR_CHSEL_0|DMA_SxCR_CHSEL_1|DMA_SxCR_CHSEL_2; //DMA chanel 7 (согласно таблице "DMA1 request mapping" RM)
DMA1_Stream5->CR|= DMA_SxCR_MSIZE_0; //Memory data size = Half-word (16 bit)
...

А зачем все эти чтения-модификации-записи??? Зачем читаете перед каждой операцией? Какой смысл? Причём ещё в много шагов.
Если откроете мануал на МК, то увидите что никакие чтения для регистров CR (ни DMA ни DAC) не нужны. И записать в них всё необходимое можно одной командой записи.
Потому и косяки что непонятно что туда пишете.
К тому же не сбрасываете флаги состояний перед стартом операции.
Вобщем: следует хотя-бы открыть мануал на МК и почитать описание регистров. Всех.

Код
#define timDac (&concat(TIMER, nTIM_dac))
#define timMp3 (&concat(TIMER, nTIM_hr))
#define dmaU   ((nDMASTR_DAC >> 3) ? &DMA2: &DMA1)
#define dmaS   (&dmaU->STREAM[nDMASTR_DAC & 7])
...
  timDac->DIER = timDac->CNT = timDac->PSC = timDac->CR[0] = 0;
  timDac->ARR = DAC_DIV - 1;
  timDac->EGR = B0;
  timDac->CR[1] = 2 << 4;
  __DMB();
  DAC.CR = 0;
  DAC.SR = B13 | B29;
  DAC.CR = (B12 | B13) << concat(DAC_DMASTR, nDMASTR_DAC) * 16 |
    (B0 | B2 | concat(DAC_TIMER, nTIM_dac, _TRGO) << 3) * (B0 | B16);
  __DMB();
  dmaU->IFCR[nDMASTR_DAC >> 2 & 1] = (B0 | B2 | B3 | B4 | B5) <<
    (nDMASTR_DAC & 3) * 6 << (nDMASTR_DAC & B1) * 2;
  dmaS->PAR = (u32)&DAC.DHR12LD;
  dmaS->MAR[1] = dmaS->MAR[0] = (u32)&smplBuf.dummy[0];
  dmaS->NDTR = DMA_CHUNK;
  dmaS->FCR = 3 << DMA_FCR_FTH | 1 << DMA_FCR_DMDIS;
  dmaS->CR = 1 << DMA_CR_EN | 1 << DMA_CR_TEIE | 1 << DMA_CR_TCIE |
    1 << DMA_CR_DIR | 1 << DMA_CR_DBM | DMAPRI_DAC << DMA_CR_PL |
    1 << DMA_CR_MINC | 2 << DMA_CR_PSIZE | 2 << DMA_CR_MSIZE |
    concat(DMAREQ_S, nDMASTR_DAC, _DAC, concat(DAC_DMASTR, nDMASTR_DAC)) <<
    DMA_CR_CHSEL;
  PinSelN(tPinmuxAoutOn);
  ENTR_CRT_SECTION();
  timMp3->CCR[0] = timMp3->CNT + mcs2clk(DAC_tWAKEUP, HrTimerCLK(H));  //по даташиту ждать после включения ЦАП >= tWAKEUP мкс
  timMp3->DIER = B1;
  EXIT_CRT_SECTION();
adnega
Цитата(jcxz @ Mar 18 2018, 17:19) *
Какой смысл?

И не понятно зачем ТС смешивает работу через HAL и через регистры?
Нужно выбрать что-то одно (только HAL).
x893
Видимо лень посмотреть примеры перед тем как код писать.
Sprite
x893
Код
Видимо лень посмотреть примеры перед тем как код писать.
И Вам хорошего дня)

jcxz
Цитата
А зачем все эти чтения-модификации-записи??? Зачем читаете перед каждой операцией? Какой смысл? Причём ещё в много шагов.
Понятно, что код инициализации ДМА можно уложить в 4 строки, записав числа в регистры PAR, M0AR, NDTR и CR. Я специально вынес каждый бит отдельно, чтобы было нагляднее. Тем более что процедура инициализации DMA выполняется один раз при старте, т.е. нет строгих временных требований к выполнению этого кода.

Цитата
следует хотя-бы открыть мануал на МК и почитать описание регистров.
Так и сделал, прочитал внимательно пункт 1 10.3.17 Stream configuration procedure:
All the stream dedicated bits set in the
status register (DMA_LISR and DMA_HISR) from the previous data block DMA
transfer should be cleared before the stream can be re-enabled.
Стало более менее понятно.

adnega, спасибо! Счастье есть) Добавил строчку
Код
DMA1->HIFCR|= DMA_HISR_HTIF5|DMA_HISR_TCIF5;
и все заработало.

В даташите также написано, что нужно после выключения DMA прочитать бит EN, т.е. проверить что он выключился. Ставить while как то "не спортивно") Подскажите как правильно? Надо ли проверять этот бит?


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.