Перейти к содержанию
    

STM32F4 DAC+DMA Normal mode

Добрый день всем участникам форума!

 

Есть задача: выводить на ЦАП массив из 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
    }

 

После первой инициализации данные выводятся, в цикле - не работает( Подозреваю, что не сбрасываю какой-то флаг.

Заранее спасибо!

Изменено пользователем Sprite

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Подозреваю, что не сбрасываю какой-то флаг.

Да, неплохо бы перед инициализацией сбрасывать статус DMA, типа

DMA2->LIFCR = (1 << DMA_LISR_HTIF0);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Какой смысл?

И не понятно зачем ТС смешивает работу через HAL и через регистры?

Нужно выбрать что-то одно (только HAL).

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 как то "не спортивно") Подскажите как правильно? Надо ли проверять этот бит?

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...