реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> STM32F4 DAC+DMA Normal mode
Sprite
сообщение Mar 18 2018, 12:56
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414



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

Есть задача: выводить на ЦАП массив из 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 - Mar 18 2018, 12:57
Go to the top of the page
 
+Quote Post
adnega
сообщение Mar 18 2018, 13:38
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



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

Да, неплохо бы перед инициализацией сбрасывать статус DMA, типа
Цитата
DMA2->LIFCR = (1 << DMA_LISR_HTIF0);
Go to the top of the page
 
+Quote Post
jcxz
сообщение Mar 18 2018, 14:19
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713



Цитата(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();
Go to the top of the page
 
+Quote Post
adnega
сообщение Mar 18 2018, 15:21
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Цитата(jcxz @ Mar 18 2018, 17:19) *
Какой смысл?

И не понятно зачем ТС смешивает работу через HAL и через регистры?
Нужно выбрать что-то одно (только HAL).
Go to the top of the page
 
+Quote Post
x893
сообщение Mar 18 2018, 16:39
Сообщение #5


Профессионал
*****

Группа: Свой
Сообщений: 1 333
Регистрация: 27-10-08
Из: Планета Земля
Пользователь №: 41 226



Видимо лень посмотреть примеры перед тем как код писать.
Go to the top of the page
 
+Quote Post
Sprite
сообщение Mar 19 2018, 03:49
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 173
Регистрация: 11-05-08
Пользователь №: 37 414



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


Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 18th July 2025 - 04:43
Рейтинг@Mail.ru


Страница сгенерированна за 0.01382 секунд с 7
ELECTRONIX ©2004-2016