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

Добрый вечер,

Не получается заставить работать DMA в STM32G030
Хорошо знакомые вещи пропускаю, наверное ошибся где-то в DMAMUX т.к. ранее с ним дел не имел.
Как понял из документации, dmamux жестко пришит к каналам контроллеров и может своей матрицей "коммутировать" запросы,
которые распараллелены по количеству каналов. Правильно?

Хотел перевести на DMA захват таймера, но сходу не заработало.
Прочитал внимательно матчасть - все равно не заработало.
Упростил. В отладчике инициирую захват и не вижу реакции со стороны DMA.

Из настроек таймера

..
  TIM1->CCMR2    |= TIM_CCMR2_CC4S_0;
  TIM1->DIER |= TIM_DIER_CC4DE ;
  TIM1->CCER     |= TIM_CCER_CC4E ;
  TIM1->CR1 |= TIM_CR1_CEN ;
..

Из референса

1.Set and configure completely the DMA channel y, except enabling the channel y.
2.Set and configure completely the related DMAMUX y channel.
3.Last, activate the DMA channel y by setting the EN bit in the DMA y channel register.
------------------
DMA      Resource
request
MUX
input
-----------------
23       TIM1_CH4
-----------------

Из настроек DMA (четвертый канал остался от предыдущего кода для другой модели)

..
        DMA1_Channel4->CPAR = (uint32_t)(&(TIM1->CCR4)) ;
        DMA1_Channel4->CNDTR = 2 ;
..
        DMAMUX1_Channel4->CCR |= DMAMUX_CxCR_DMAREQ_ID_4|DMAMUX_CxCR_DMAREQ_ID_2|DMAMUX_CxCR_DMAREQ_ID_1|DMAMUX_CxCR_DMAREQ_ID_0 ; // 23
..
        DMA1_Channel4->CCR |= DMA_CCR_EN ;
..

На входе таймера постоянный потенциал, захватываю и вызываю DMA принудительно

TIM1->EGR = TIM_EGR_CC4G ;

Проверяю регистр DMA, счетчик не уменьшился

DMA1_Channel4->CNDTR = 2

 

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

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


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

Не работал с ПДП на G0x, но посмотрел документацию и заметил, что в DMA каналы нумеруются с 1, а в DMAMUX с нуля. Возможно, надо использовать DMAMUX1_Channel3->CCR?

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


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

Спасибо. Помогло. Не обратил внимания на индексы в диаграмме устройства dmamux. Глянул сейчас в cmsis, и действительно каналы с нуля.

$ grep -R DMAMUX1_Ch ../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/ |grep g030
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel0_BASE    (DMAMUX1_BASE)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel1_BASE    (DMAMUX1_BASE + 0x00000004UL)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel2_BASE    (DMAMUX1_BASE + 0x00000008UL)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel3_BASE    (DMAMUX1_BASE + 0x0000000CUL)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel4_BASE    (DMAMUX1_BASE + 0x00000010UL)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_ChannelStatus_BASE      (DMAMUX1_BASE + 0x00000080UL)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel0       ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel0_BASE)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel1       ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel1_BASE)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel2       ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel2_BASE)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel3       ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel3_BASE)
../../STM32CubeG0-master/Drivers/CMSIS/Device/ST/STM32G0xx/Include/stm32g030xx.h:#define DMAMUX1_Channel4       ((DMAMUX_Channel_TypeDef *) DMAMUX1_Channel4_BASE)

 

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


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

On 9/20/2024 at 8:00 PM, ozforester said:
DMAMUX1_Channel4->CCR |= DMAMUX_CxCR_DMAREQ_ID_4|DMAMUX_CxCR_DMAREQ_ID_2|DMAMUX_CxCR_DMAREQ_ID_1|DMAMUX_CxCR_DMAREQ_ID_0 ; // 23

 

Зачем вы применяете чтение-модификацию-запись ?
Мультиплексор не может сразу несколько каналов выбрать.
Мультиплексов всегда только один канал выбирает.
Поэтому надо просто запись делать.

Вы таймер правильно настроили ?
Вы GPIO под этот таймер правильно настроили ?

С G0 не сталкивался, но в H7 применял для UART. У них DMA и DMAMUX одинаково сделаны.

Вот мой вариант приема по UART

Spoiler
void init()
{
	RCC->APB1LENR |= RCC_APB1LENR_UART4EN;
	RCC->AHB1ENR |= RCC_AHB1ENR_DMA1EN;

	pin_init();

	UART4->CR1 = 0;
	UART4->CR1 = 0 |
				 USART_CR1_RE |
				 USART_CR1_TE |
				 USART_CR1_TCIE |
				 (8UL << USART_CR1_DEAT_Pos) |
				 (8UL << USART_CR1_DEDT_Pos);

	UART4->CR2 = 0; // 1 stop
	UART4->CR3 = USART_CR3_DEM; // no flow control
	UART4->BRR = 618;
	UART4->CR1 |= USART_CR1_UE;

	DMAMUX1_Channel1->CCR = 63; // uart4_rx_dma

	DMA1_Stream1->CR = (0UL << DMA_SxCR_DIR_Pos) 	| 	/* data transfer direction - peripheral-to-memory */
					   (1UL << DMA_SxCR_MINC_Pos) 	| 	/* memory address pointer is incremented after each data transfer */
					   (0UL << DMA_SxCR_PSIZE_Pos)	| 	/* peripheral data size - byte (8-bit) */
					   (0UL << DMA_SxCR_MSIZE_Pos)	; 	/* memory data size - byte (8-bit) */
	DMA1_Stream1->M0AR = (uint32_t)rs485_rx;
	DMA1_Stream1->PAR = (uint32_t)&UART4->RDR;			/* peripheral address */
	DMA1_Stream1->NDTR = MB_BUF_SZ;
	DMA1_Stream1->FCR = 0;
}

void start_rx()
{
   // Start Rx DMA

	DMA1_Stream1->CR &= ~DMA_SxCR_EN;

	DMA1->LIFCR = (0x3DUL << 6);

	DMA1_Stream1->M0AR = (uint32_t)rs485_rx;
	DMA1_Stream1->NDTR = MB_BUF_SZ;

	UART4->RTOR = 12UL;
	UART4->CR1 |= USART_CR1_RTOIE;
	UART4->CR2 |= USART_CR2_RTOEN;

	UART4->ICR = USART_ICR_RTOCF;
	UART4->CR3 |= USART_CR3_DMAR; // DMA enable receiver

	DMA1_Stream1->CR |= DMA_SxCR_EN;
}

 

 

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


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

Когда нет явного указания в документации про досуп к регистру, то делаю чтение-запись, и иногда несколькими отдельными операциями. Это  при отладке, поиске проблемы, изучении. В рабочем варианте можно оптимизировать.

В знакомых мелочах трудно ошибиться, поэтому и выкинул лишнее. оставил только существенные моменты. Спасибо за пример, может когда-нибудь и до Н7 доберусь.

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

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


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

On 9/20/2024 at 9:51 PM, ozforester said:

Когда нет явного указания в документации про досуп к регистру, то делаю чтение-запись, и иногда несколькими отдельными операциями.

нет, а если вы раньше уже настроили какой-то другой канал и теперь поверх этой настройки пытаетесь внести новую настройку.

On 9/20/2024 at 9:51 PM, ozforester said:

Спасибо за пример, может когда-нибудь и до Н7 доберусь.

Я не внимательно посмотрел. Действительно, у Н7 и DMA и DMAMUX начинаются с нуля. А у G0 DMA с 1, а DMAMUX с 0, как выше уже написал Сергей Борщ и как вы сами в этом убедились.

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


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

Ну, там в рефренсе каждый раз пишут что один канал - один запрос, что полагаются на сообразительность пользователя. (= Ресет в RCC у DMA есть, наверное бы добавил сброс  в инициализацию.  Это да, сначала ленюсь, так как простая задача и все регистры по дефолту, а потом приходится переделывать инициализацию и заново проверять.

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

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


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

1 час назад, dimka76 сказал:

Вот мой вариант приема по UART

void start_rx()
{
	DMA1_Stream1->CR &= ~DMA_SxCR_EN;
  ...
}

Я сейчас на память не вспомню точно, но вроде после выключения DMA-потока нужно дождаться, пока он выключится.

Хотя, возможно, это требуется только при принудительном выключении работающего потока, который еще и FIFO использует...

P.S. Кстати. А зачем включать/выключать DMA-поток на прием UART?

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


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

On 9/20/2024 at 10:43 PM, Arlleex said:

P.S. Кстати. А зачем включать/выключать DMA-поток на прием UART?

все из примеров ))) 

STM говорит, что перед настройкой надо выключать.

Да, на самом деле, надо дождаться того, что он выключился, но мне похоже повезло и помогло то, что 

после выключения я еще одну операцию делаю, а потом меняю настройку.

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


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

54 минуты назад, dimka76 сказал:

все из примеров ))) 

STM говорит, что перед настройкой надо выключать.

Понял🙂Но не понял, зачем перенастраивать? Один раз включил - и разгребаешь поток потом. Или у Вас какой-то там хитрый протокол? Но все равно странно.

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


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

On 9/20/2024 at 11:51 PM, Arlleex said:

Но не понял, зачем перенастраивать? 


В Reference Manual на микроконтроллере четко описана процедура настройки (перенастройки) и не описывается почему именно так надо делать.

Так же там написано, что сбрасывать флаги надо при выключенном канале.

Quote

All the stream dedicated bits set in the status register (DMA_LISR and DMA_HISR) from the previous data block DMA transfer must be cleared before the stream can be re-enabled.

Регистр количества принимаемых данных при каждом принятом байте инкрементируется.
А для приема следующей пачки данных значение этого регистра надо опять задать новое.
Но пока канал включен регистр количества данных только для чтения

Quote

DMA stream x number of data register (DMA_SxNDTR)
Bits 15:0 NDT[15:0]: number of data items to transfer (0 up to 65535)
                  This register can be written only when the stream is disabled. When the stream is enabled,
                  this register is read-only, indicating the remaining data items to be transmitted.

 

 

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


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

2 часа назад, dimka76 сказал:


В Reference Manual на микроконтроллере четко описана процедура настройки (перенастройки) и не описывается почему именно так надо делать.

Так же там написано, что сбрасывать флаги надо при выключенном канале.

Регистр количества принимаемых данных при каждом принятом байте инкрементируется.
А для приема следующей пачки данных значение этого регистра надо опять задать новое.
Но пока канал включен регистр количества данных только для чтения

 

Ды это то все понятно. Я про общий концепт. Зачем в принципе дергать включение/выключение/перенастройку DMA-стрима на прием UART? Любой DMA умеет кольцевой режим - не проблема организовать однократную настройку при старте ПО и выгрeбать данные из очереди, в которую подпихивает DMA.

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


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

8 часов назад, Arlleex сказал:

Ды это то все понятно. Я про общий концепт. Зачем в принципе дергать включение/выключение/перенастройку DMA-стрима на прием UART?

Например - для того, чтобы отдать DMA-канал другой периферии. Не знаю как с этим обстоит дело в STM dimka76, но ведь во многих STM32 запросы периферии прибиты гвоздями к DMA-каналам. И нельзя перебросить запрос от конкретной периферии на произвольный DMA-канал.

В моём 3D-принтере (на STM32F103) глупый китайский разработчик схемы посадил две быстрых периферии (UART и SPI) на такие номера, которые используют один и тот же DMA-канал. Поэтому никак не возможно пользоваться DMA одновременно.   :sad:

Также ещё бывает нужно положить МК в сон например. Выключив работу UART.

10 часов назад, dimka76 сказал:

Так же там написано, что сбрасывать флаги надо при выключенном канале.

Вы не поняли смысла той фразы. Та фраза требует, чтобы до запуска нового трансфера, статусные флаги от предыдущего трансфера были бы очищены. Потому как сами они не очищаются при останове и переразрешении DMA-канала.

Иначе сами подумайте: как тогда работать с многоблочными трансферами? Как чистить флаги в них? Те же - TCIF и HTIF. И зачем тогда они нужны (TCIF и HTIF), если их нельзя очистить в процессе трансфера?

Нормально флаги чистятся и при работающем трансфере. И устанавливаются потом при следующем событии. По флагам TCIF/HTIF мои драйвера определяют - какой именно буфер нужно обрабатывать в многоблочных трансферах на STM32.

12 часов назад, Arlleex сказал:

Я сейчас на память не вспомню точно, но вроде после выключения DMA-потока нужно дождаться, пока он выключится.

Стараюсь нигде (по возможности конечно) не выключать работающий DMA принудительно. Имхо - это плохое решение. Как-то я много накувыркался с одним проектом, где предыдущий разработчик делал такое принудительное выключение: И данные в FIFO DMA там застревали (и этого никак не видно и никак их не сбросить) и необслуженные DMA-запросы повисали и не сбрасывались, и потом приводили к сбою в следующем трансфере. Чтобы это всё корректно очистить, пришлось сделать множество дополнительных телодвижений в коде.

Гораздо лучше (в случае многоблочного трансфера на link-list-передаче) делать останов трансфера выставлением стоп-условия в следующем блоке регистров управления, который лежит ещё в ОЗУ (или в неактивном (теневом) наборе регистров). Так останов трансфера выглядит для DMA-контроллера как штатный останов. И ничего нигде не залипает. Если конечно такое возможно в данном МК.

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


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

36 минут назад, jcxz сказал:

Например - для того, чтобы отдать DMA-канал другой периферии. Не знаю как с этим обстоит дело в STM dimka76, но ведь во многих STM32 запросы периферии прибиты гвоздями к DMA-каналам. И нельзя перебросить запрос от конкретной периферии на произвольный DMA-канал.

Понятно. Стараюсь никогда так не делать и заранее разносить все еще до этапа схематика и выпуска платы.

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


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

On 9/21/2024 at 2:43 AM, Arlleex said:

Ды это то все понятно. Я про общий концепт. Зачем в принципе дергать включение/выключение/перенастройку DMA-стрима на прием UART? Любой DMA умеет кольцевой режим - не проблема организовать однократную настройку при старте ПО и выгрeбать данные из очереди, в которую подпихивает DMA.

Можно придумать кучу алгоритмов приема данных и каждый будет по своему хорош.
У меня сделано так.
По UART ведется работа в диалоговом режиме. Мастер отправляет запросы ведомому. Пока мастер не получит ответ на запрос, новый запрос не отправляет.
Микроконтроллер здесь выступает в роли подчиненного.
Запросы могут быть разной длины.
В микроконтроллере объявляется массив принимаемых данных размером чуть больше самого длинного запроса (не спрашивайте зачем, я так решил, памяти с избытком).
В Н7 есть возможность настроить прерывание по длительности паузы во входящем потоке. Время паузы можно регулировать.
Размер принимаемых данных DMA настраивается на размер массива данных.
Когда сработает прерывание по паузе приема смотрим какой в DMA остаток. Отсюда получаем размер принятых данных.
После обработки принятого запроса надо опять восстановить размер принимаемых данных в DMA, а для этого его надо выключить, а затем снова включить

On 9/21/2024 at 11:03 AM, jcxz said:

Вы не поняли смысла той фразы.

Я не так хорошо знаю английский и часто прибегаю к помощи on-line переводчика.

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


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

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

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

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

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

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

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

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

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

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