esaulenka 7 20 июля, 2018 Опубликовано 20 июля, 2018 · Жалоба Не забывайте только, что одна транзакция DMA Burst не должна пересекать границу 1кБ (вроде), это связано с физическими адресуемыми подчиненными шин. Какие интересные грабли. Это каких именно процессоров касается? И где описано? Этак burst можно применять только в очень ограниченном числе случаев... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 173 20 июля, 2018 Опубликовано 20 июля, 2018 · Жалоба Какие интересные грабли. Это каких именно процессоров касается? И где описано? Это не грабли. Это документированная особенность построения ядра ARMv7M. В других версиях архитектуры аналогично, только адресная граница физических slave-подсистем (например, памяти) может отличаться от 1кБ. Поэтому, если, например, Вы запустите burst-транзакцию, пересекающую адресную границу одного подчиненного, DMA завершит транзакцию успешно (во флагах статуса), но в действительности часть данных потеряется. Причем DMA не взведет флаги Transfer Error. Ну в STM32 по крайней мере точно так. Вот Вам выдержка из Reference Manual на STM32F4xx, например: The burst configuration has to be selected in order to respect the AHB protocol, where bursts must not cross the 1 KB address boundary because the minimum address space that can be allocated to a single slave is 1 KB. This means that the 1 KB address boundary should not be crossed by a burst block transfer, otherwise an AHB error would be generated, that is not reported by the DMA registers. Этак burst можно применять только в очень ограниченном числе случаев... Ну нет, почему же. Если необходимо передавать данные в периферию, имеющую FIFO, то одной burst-транзакцией можно сразу заполнить в нем место, и пусть отправляет куда хочет там. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
esaulenka 7 20 июля, 2018 Опубликовано 20 июля, 2018 · Жалоба Да, неправ, это место просмотрел... Благо объемы у меня небольшие, и разгонять DMA не требуется - до включения burst'а руки так и не дошли... Но это означает, что работу с буфером больше 1кБ надо обкладывать дополнительными проверками. И маленький буфер тоже по-хорошему выравнивать надо (блин, как же в gcc это неудобно...). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 20 июля, 2018 Опубликовано 20 июля, 2018 · Жалоба И маленький буфер тоже по-хорошему выравнивать надо На рахмер строки кэша (32 байта) да. Я так понимаю речь про килобайт? Так это можно и в динамике сделать (делить на chunks передаваемые блоки). Но это все на этапе проектирования понятно - можно менеджера памяти нагрузить требованиями по выравниванию, например. Если он есть, конечно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 173 20 июля, 2018 Опубликовано 20 июля, 2018 · Жалоба Но это означает, что работу с буфером больше 1кБ надо обкладывать дополнительными проверками. И маленький буфер тоже по-хорошему выравнивать надо (блин, как же в gcc это неудобно...). Если речь про ограничение в 1кБ - то не забывайте, это только для burst-передач, которые, в общем-то, обычно ограничены десятками-сотней байт. Если это обычная транзакция DMA (не burst) - можете передавать сколько угодно, ограничение только DMA делает на количество данных, передаваемых в одном сеансе транзакции (для STM32 это 64кБ). Но это все на этапе проектирования понятно - можно менеджера памяти нагрузить требованиями по выравниванию, например. Если он есть, конечно. ИМХО, лучше сразу все продумать на этапе составления программы и разлиновки памяти. Динамические диспетчеры так или иначе такты процессора тратят. И тем более было бы ради чего - а тут все буфера статически разместить можно еще на этапе обдумывания структуры проекта. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 27 декабря, 2019 Опубликовано 27 декабря, 2019 · Жалоба Делал работу с видеопамятью через MDMA - заполнение и копирование прямоугольных областей. Выяснилось, что в случае двухбайтовых пикселей в поле MDMA_CBNDTR_BNDT приходится писать количество пикселей умноженное на четыре. При этом поля MDMA_CBRUR_SUV и MDMA_CBRUR_DUV исчисляются как и положено, в байтах... Вопрос... У кого есть опыт ходьбы по этим граблям? Так ли обстоят дела, как мне показалось? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 48 28 декабря, 2019 Опубликовано 28 декабря, 2019 (изменено) · Жалоба В 20.07.2018 в 09:50, esaulenka сказал: Какие интересные грабли. Это каких именно процессоров касается? И где описано? Интересно. В СТМ ДМА не использовал таким образом, а вот в IMX Allwinner-ах по полной, т.е. перекидывал целиком экранные области по 32 байта за бурст, размеры больше 1 Мбайта и на такое никогда не натыкался, походу это или косяки СТМшиков или именно данной архитектуры. Изменено 28 декабря, 2019 пользователем mantech Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 28 декабря, 2019 Опубликовано 28 декабря, 2019 · Жалоба 10 hours ago, GenaSPB said: Вопрос... У кого есть опыт ходьбы по этим граблям? Так ли обстоят дела, как мне показалось? Приходилось использовать MDMA по причине того, что он может менять последовательность байт при передаче, что очень важно при пересылке буфера в LCD (иначе пришлосб бы менять байты вручную через _rev16). Всё исправно работает, ниже код. Правда, пришлось повозиться с настройками. static void MX_MDMA_Init(void) { /* MDMA controller clock enable */ __HAL_RCC_MDMA_CLK_ENABLE(); /* Local variables */ /* Configure MDMA channel MDMA_Channel7 */ /* Configure MDMA request hmdma_mdma_channel7_sw_0 on MDMA_Channel7 */ hmdma_mdma_channel7_sw_0.Instance = MDMA_Channel7; hmdma_mdma_channel7_sw_0.Init.Request = MDMA_REQUEST_SW; hmdma_mdma_channel7_sw_0.Init.TransferTriggerMode = MDMA_FULL_TRANSFER; hmdma_mdma_channel7_sw_0.Init.Priority = MDMA_PRIORITY_LOW; hmdma_mdma_channel7_sw_0.Init.Endianness = MDMA_LITTLE_BYTE_ENDIANNESS_EXCHANGE; //Меняем местами байты (для LCD) hmdma_mdma_channel7_sw_0.Init.SourceInc = MDMA_SRC_INC_HALFWORD; hmdma_mdma_channel7_sw_0.Init.DestinationInc = MDMA_DEST_INC_DISABLE; hmdma_mdma_channel7_sw_0.Init.SourceDataSize = MDMA_SRC_DATASIZE_HALFWORD; hmdma_mdma_channel7_sw_0.Init.DestDataSize = MDMA_DEST_DATASIZE_HALFWORD; hmdma_mdma_channel7_sw_0.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; hmdma_mdma_channel7_sw_0.Init.BufferTransferLength = 2; //1 для BYTE, 2 для HALFWORD, 4 для WORD hmdma_mdma_channel7_sw_0.Init.SourceBurst = MDMA_SOURCE_BURST_SINGLE; hmdma_mdma_channel7_sw_0.Init.DestBurst = MDMA_DEST_BURST_SINGLE; hmdma_mdma_channel7_sw_0.Init.SourceBlockAddressOffset = 0; hmdma_mdma_channel7_sw_0.Init.DestBlockAddressOffset = 0; if (HAL_MDMA_Init(&hmdma_mdma_channel7_sw_0) != HAL_OK) { Error_Handler(); } } void SaI2xTransfer(void) { HAL_MDMA_PollForTransfer(&hmdma_mdma_channel7_sw_0,HAL_MDMA_FULL_TRANSFER,100); SaI2x((u8*)&BufferAndBorder[(1+160+2)+1],1+160+2,FilterBuffer,LCD_W<<1,160,120); SCB_CleanDCache(); HAL_MDMA_Start(&hmdma_mdma_channel7_sw_0,(u32)FilterBuffer,(u32)&LCD_DAT32,((LCD_H*LCD_W)<<1)/3,3); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 28 декабря, 2019 Опубликовано 28 декабря, 2019 (изменено) · Жалоба Полуторный размер? Предпоследний параметр функции HAL_MDMA_Start.... судя по всему у вас такой проблемы не проявилось. Изменено 28 декабря, 2019 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
repstosw 18 28 декабря, 2019 Опубликовано 28 декабря, 2019 · Жалоба 2 hours ago, GenaSPB said: Полуторный размер? Предпоследний параметр функции HAL_MDMA_Start.... судя по всему у вас такой проблемы не проявилось. Одна DMA-транзакция: не более 65535 байт за 1 раз. Пришлось бить на 3 равные части: LCD_H*LCD_W)<<1)/3 ((400*240 пикспелей) *2 байт) /3 = 64000 байт. По три раза(последний аргумент). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GenaSPB 11 28 декабря, 2019 Опубликовано 28 декабря, 2019 (изменено) · Жалоба Понял. Хоть у вас по 16 бит написано... размер задаётся как надо. Странно. Что за ненормальность у меня... Изменено 28 декабря, 2019 пользователем GenaSPB Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GFX 0 23 апреля, 2020 Опубликовано 23 апреля, 2020 · Жалоба Добрый день. Делал замер скорости ДМА и оказалось, что МДМА очень медленно работает. Пересылка память ту память всего на 43 МГц работает AXI_SRAM->МДМА -> AXI_SRAM, обычный ДМА еще медленее 16 Мгц. Серия F4 быстрее, это как так вышло то у STM? либо есть какой-то нюанс. Кэши все включены, скорость мк 480 Мгц. Пересылка 16 бит. Причем с переферией типа портов вводы-вывода обычный ДМА шустрее работает, если в память SRAM1, но тоже медленно. Тот же FMC 34Мгц через МДМА. через ДМА 20 Мгц, а должен 120Мгц держать, так вот как заставить его с частотой 120 Мгц работать, если ДМА еле передают данные? даже еще хуже, 17 Мгц FMC -> МДМА -> AXI_SRAM или SRAM1 для МДМА все равно в какую память один фиг медленно. Обычный ДМА чуть шустрее, если в SRAM1 но все равно медленно, что это за скорость 20 Мгц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 48 24 апреля, 2020 Опубликовано 24 апреля, 2020 · Жалоба 11 часов назад, GFX сказал: Обычный ДМА чуть шустрее, если в SRAM1 но все равно медленно, что это за скорость 20 Мгц. А клоки или делители поднастроить нельзя там разве? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GFX 0 24 апреля, 2020 Опубликовано 24 апреля, 2020 · Жалоба 10 часов назад, mantech сказал: А клоки или делители поднастроить нельзя там разве? Чего именно? Итак все на максимум Спойлер /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; /** Supply configuration update enable */ HAL_PWREx_ConfigSupply(PWR_LDO_SUPPLY); /** Configure the main internal regulator output voltage */ __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE0); while(!__HAL_PWR_GET_FLAG(PWR_FLAG_VOSRDY)) {} /** Configure LSE Drive Capability */ HAL_PWR_EnableBkUpAccess(); __HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW); /** Macro to configure the PLL clock source */ __HAL_RCC_PLL_PLLSOURCE_CONFIG(RCC_PLLSOURCE_HSE); /** Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.LSEState = RCC_LSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLM = 5; RCC_OscInitStruct.PLL.PLLN = 192; RCC_OscInitStruct.PLL.PLLP = 2; RCC_OscInitStruct.PLL.PLLQ = 20; RCC_OscInitStruct.PLL.PLLR = 2; RCC_OscInitStruct.PLL.PLLRGE = RCC_PLL1VCIRANGE_2; RCC_OscInitStruct.PLL.PLLVCOSEL = RCC_PLL1VCOWIDE; RCC_OscInitStruct.PLL.PLLFRACN = 0; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2 |RCC_CLOCKTYPE_D3PCLK1|RCC_CLOCKTYPE_D1PCLK1; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB3CLKDivider = RCC_APB3_DIV2; RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_APB2_DIV2; RCC_ClkInitStruct.APB4CLKDivider = RCC_APB4_DIV2; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC|RCC_PERIPHCLK_HRTIM1 |RCC_PERIPHCLK_SPI2|RCC_PERIPHCLK_SDMMC |RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_USB |RCC_PERIPHCLK_QSPI|RCC_PERIPHCLK_FMC; PeriphClkInitStruct.PLL2.PLL2M = 2; PeriphClkInitStruct.PLL2.PLL2N = 12; PeriphClkInitStruct.PLL2.PLL2P = 1; PeriphClkInitStruct.PLL2.PLL2Q = 2; PeriphClkInitStruct.PLL2.PLL2R = 2; PeriphClkInitStruct.PLL2.PLL2RGE = RCC_PLL2VCIRANGE_3; PeriphClkInitStruct.PLL2.PLL2VCOSEL = RCC_PLL2VCOMEDIUM; PeriphClkInitStruct.PLL2.PLL2FRACN = 0; PeriphClkInitStruct.FmcClockSelection = RCC_FMCCLKSOURCE_D1HCLK; PeriphClkInitStruct.QspiClockSelection = RCC_QSPICLKSOURCE_D1HCLK; PeriphClkInitStruct.SdmmcClockSelection = RCC_SDMMCCLKSOURCE_PLL; PeriphClkInitStruct.Spi123ClockSelection = RCC_SPI123CLKSOURCE_PLL2; PeriphClkInitStruct.UsbClockSelection = RCC_USBCLKSOURCE_PLL; PeriphClkInitStruct.AdcClockSelection = RCC_ADCCLKSOURCE_PLL2; PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE; PeriphClkInitStruct.Hrtim1ClockSelection = RCC_HRTIM1CLK_CPUCLK; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) { Error_Handler(); } /** Enable USB Voltage detector */ HAL_PWREx_EnableUSBVoltageDetector(); } Спойлер /* FMC initialization function */ static void MX_FMC_Init(void) { /* USER CODE BEGIN FMC_Init 0 */ /* USER CODE END FMC_Init 0 */ FMC_NORSRAM_TimingTypeDef Timing = {0}; /* USER CODE BEGIN FMC_Init 1 */ /* USER CODE END FMC_Init 1 */ /** Perform the SRAM1 memory initialization sequence */ hsram1.Instance = FMC_NORSRAM_DEVICE; hsram1.Extended = FMC_NORSRAM_EXTENDED_DEVICE; /* hsram1.Init */ hsram1.Init.NSBank = FMC_NORSRAM_BANK1; hsram1.Init.DataAddressMux = FMC_DATA_ADDRESS_MUX_DISABLE; hsram1.Init.MemoryType = FMC_MEMORY_TYPE_SRAM; hsram1.Init.MemoryDataWidth = FMC_NORSRAM_MEM_BUS_WIDTH_16; hsram1.Init.BurstAccessMode = FMC_BURST_ACCESS_MODE_DISABLE; hsram1.Init.WaitSignalPolarity = FMC_WAIT_SIGNAL_POLARITY_LOW; hsram1.Init.WaitSignalActive = FMC_WAIT_TIMING_BEFORE_WS; hsram1.Init.WriteOperation = FMC_WRITE_OPERATION_ENABLE; hsram1.Init.WaitSignal = FMC_WAIT_SIGNAL_DISABLE; hsram1.Init.ExtendedMode = FMC_EXTENDED_MODE_DISABLE; hsram1.Init.AsynchronousWait = FMC_ASYNCHRONOUS_WAIT_DISABLE; hsram1.Init.WriteBurst = FMC_WRITE_BURST_ENABLE;//FMC_WRITE_BURST_DISABLE; hsram1.Init.ContinuousClock = FMC_CONTINUOUS_CLOCK_SYNC_ONLY; hsram1.Init.WriteFifo = FMC_WRITE_FIFO_ENABLE; hsram1.Init.PageSize = FMC_PAGE_SIZE_NONE;// /* Timing */ Timing.AddressSetupTime = 0; Timing.AddressHoldTime = 0; Timing.DataSetupTime = 1; Timing.BusTurnAroundDuration = 0; Timing.CLKDivision = 0; Timing.DataLatency = 0; Timing.AccessMode = FMC_ACCESS_MODE_A; /* ExtTiming */ if (HAL_SRAM_Init(&hsram1, &Timing, NULL) != HAL_OK) { Error_Handler( ); } /* USER CODE BEGIN FMC_Init 2 */ /* USER CODE END FMC_Init 2 */ } Даже проц закидывает в память со скоростью 43Мгц из FMC, т.е. сам проц быстрый, а толку нет, периферия еще медленнее чем была. AXI_SRAM->ПРОЦ ДКЕШ->SRAM1 = 188МГц, но МДМА всего 17Мгц в том же случае да и вообще при любой памяти. ДМА в этом случае всего 16 Мгц, но обычный ДМА не на AXI шине так что это понятно, с периферией в SRAM1 обычный ДМА пошустрее МДМА скидывает, но все равно медленно все это. Как FMC заставить на 120 Мгц работать то, если его даже проц не раскачигаривает на такую скорость. Считывание с FMC-> проц->AXI_SRAM 43 МГц, FMC->МДМА->AXI_SRAM - 17 МГц, FMC->ДМА->SRAM1 (1 или 2 не важно) - 20 МГц. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mantech 48 24 апреля, 2020 Опубликовано 24 апреля, 2020 · Жалоба 1 час назад, GFX сказал: Даже проц закидывает в память со скоростью 43Мгц из FMC Странно. Нафига тогда 100 или 133МГц клок для памяти если шина в 2 раза медленнее. Только ради видеопорта что-ли... В А серии это решается за счет увеличения разрядности шины, тут не в курсе, может тоже что есть. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться