Jump to content

    

__inline__

Участник
  • Content Count

    870
  • Joined

Everything posted by __inline__


  1. У меня сомнения в том, что по входу включение не-дифференциальное : сигнал снимается с ножки выхода ЦАП (диапазон напряжения 0 В ...+VREF В) относительно AGND , которая организована как отдельный полигон и соединяется с полигоном цифровой земли через резистор 0 Ом в единственном месте. Боюсь, что перепады напряжения питания Li-Ion аккумулятора (общий ток потребления устройства 0.25 А максимум) будет наводить помеху в AGND через GND. На цифровые узлы свой LDO, который из 3.7 В Li-Ion делает 3.3 В (ток до 0.5 А максимально). Shutdown в схеме всегда посажен на землю (без управления от МК). Землю микросхемы УНЧ садить на аналоговую или цифровую(общую) ? Или всё-же подать питание на УНЧ от LDO, который используется для AVCC +VREF для STM32. И землю подключить к AGND STM32 ? Схема ниже. Пока запитал УНЧ от аналогового LDO (который также питает ЦАП и аналоговые цепи внутри STM32): свои AVCC и AGND. На схеме FB - ферритовая бусина. 3A3 - аналоговое питание 3.3V. A - аналоговая GND
  2. Доброе время суток! Исходный звуковой сигнал (полоса частот 60 Гц - 24 кГц) беру с выхода ЦАП STM32, напряжение VREF хорошего качества - аналоговая земля, на AVCC свой стабилизатор напряжения LDO 3.3 В. Сигнал поступает на вход УНЧ на микросхеме LM4871, которая представляет собой мостовой УНЧ (нагрузка подключается гальванически напрямую к выходам двух ОУ без земли). Рисунок ниже. Выход ЦАП относительно Analog GND. Можно ли запитать УНЧ LM4871 напрямую от литиевого аккумулятора 3.7V, а не через аналоговый LDO 3.3V (который для опоры ЦАП STM32) без опасения, что помехи по цепи питания (микроконтроллер STM32 400 МГц + цифровые узлы) наведут шум тракте НЧ ?
  3. Это здОрово, что есть уже аппаратное решение. Но в моём случае - возможность воспроизведения видео-потоков PackMan и H264 - это "ОДНА ИЗ ВСЕХ" возможностей, которых много. Поэтому гибче софтово было решить.
  4. Оказывается, эта проблема существует уже много лет : https://community.st.com/s/question/0D50X00...-of-stm32f407ig
  5. Всем привет! :rolleyes: :1111493779: В связи с освоением процессора STM32H743 на базе отладочной платы Nucleo-H743, были сделаны перенос и модификация Lossless кодека PackMan на разрешение 320x240. Ветка получила кодовое название "PackMan320". Подробнее вместе с исходными текстами программ тут: http://vrtp.ru/index.php?showtopic=29688&st=150 Видео(PackMan320 + FLAC) : http://www.youtube.com/watch?v=s2a_DqrIFaw Ну и попутно ещё сделал декодеры MP4(точнее H.264, пофиксил, у китайцев в коде была ошибка, приводящая к артефактам ) и MP3. Видео: http://www.youtube.com/watch?v=x3sADTqlfj8 Более подробнее - там же: http://vrtp.ru/index.php?showtopic=29688&st=150
  6. STM32H743 и SDIO

    Заимплементировал SDIO в работе декодера видео + FLAC. Переписал Хало-Куб для работы с картами в HIGH_SPEED Mode. У Куба 2 крайности: либо карта в Standard Mode, либо в Ultra High Speed Mode (с понижением питания до 1.8V). Мне же Ultra HS Mode не подошёл, так как питание карты 3.3V. Поэтому сделал поддержку High Speed Mode (3.3V). Частотомер выдал на SDIO CLK 48,6 МГц (вместо теоретических 50 МГц). Подробнее тут: http://vrtp.ru/index.php?showtopic=29688&st=150 Там же исходники (High Speed Mode отключен, включить его - раскомментарить последнюю строку в main.c). Видео в действии: http://www.youtube.com/watch?v=s2a_DqrIFaw
  7. STM32H743 и SDIO

    Пробовал все линии и по-очереди делать в LOW. Без бусины тоже не работало, даже при CLK < 1 МГц. И это Куб изначально выставил, а не я :) Был бы у меня глаз осциллограф, можно было посмотреть форму сигнала...... Соглашусь с ув. aaarrr, ферритовая бусина как раз душит СВЧ-всплески, от которых карта может несанкционированно передёргиваться. Это макет. Сделать короче уже трудновато, много другой периферии висит. На релизе будет печатная плата с земляными полигонами и всё как надо. Но футпринт заложить на резистор/бусину не помешает. Мне удалось повысить SD CLK до 48 МГц - карта работает, прикрутил FatFs (не та, то с Куб-ом идёт, а свою отлаженную версию). MP3-файл декодируется нормально. На 96 МГц уже не работает. Никакими командами перевода в High Speed Mode не пользовался, просто увеличил CLK до 48 МГц. Все три карты работают. Спрашивается, зачем нужна команда для перевода в High Speed Mode, когда она при 3,3V нормально работает на быстром клоке 48..50МГц ? В файле stm32h7xx_hal_sd.c сделать изменения в функции HAL_SD_ConfigWideBusOperation(): //.............. #if 0 /* Check if user Clock div < Normal speed 25Mhz, no change in Clockdiv */ if(hsd->Init.ClockDiv >= SDMMC_NSpeed_CLK_DIV) { Init.ClockDiv = hsd->Init.ClockDiv; } else { if(hsd->SdCard.CardSpeed == CARD_ULTRA_HIGH_SPEED) { Init.ClockDiv = hsd->Init.ClockDiv; } else { /* No High speed SD card */ Init.ClockDiv = SDMMC_NSpeed_CLK_DIV; } } #endif Init.ClockDiv = hsd->Init.ClockDiv; //!!! снимаем ограничение на SD CLK SDMMC_Init(hsd->Instance, Init); //.......
  8. STM32H743 и SDIO

    Укоротил все линии соединения с SD карточкой до 4 см. Подключил карту к AVCC/AGND. На провод SDIO CLK надел ферритовую втулку. Между выводом питания и землями на карте - три конденсатора: 0,1 мкф(керамика) + 10 мкФ(тантал) + 220 мкФ(электролит) Заработали все три карты! Пробовал убирать ферритовую втулку с SDIO_CLK и понижать частоту SDIO CLK - карты не работают. Инит карты такой (HAL, Cube): static void MX_SDMMC1_SD_Init(void) { hsd1.Instance = SDMMC1; hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_RISING; hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE; hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B; hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_DISABLE; hsd1.Init.ClockDiv = 0; } Частотомером обнаружил, что Куб не даёт сделать частоту SD CLK выше, чем 24.176 МГц. Иными словами, все делители hsd1.Init.ClockDiv, меньшие чем 4 - не прокатывают - частота 24.176 МГц. Снять это ограничение можно, расковыряв HAL Куба. Ниже частоты SD CLK, измеренные частотомером и значения hsd1.Init.ClockDiv: На сильно низких частотах касание щупа частотомера к SD CLK приводит к повисанию SD карты. GPIO настроены так (на всех линиях -встроенные PULL UP, кроме CLK. Внешних резисторов нет): void HAL_SD_MspInit(SD_HandleTypeDef* hsd) { GPIO_InitTypeDef GPIO_InitStruct; if(hsd->Instance==SDMMC1) { /* USER CODE BEGIN SDMMC1_MspInit 0 */ /* USER CODE END SDMMC1_MspInit 0 */ /* Peripheral clock enable */ __HAL_RCC_SDMMC1_CLK_ENABLE(); /**SDMMC1 GPIO Configuration PC8 ------> SDMMC1_D0 PC9 ------> SDMMC1_D1 PC10 ------> SDMMC1_D2 PC11 ------> SDMMC1_D3 PC12 ------> SDMMC1_CK PD2 ------> SDMMC1_CMD */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11; // |GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; //!!! включить подтяжки! GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); //C12 => CK, NO PULL GPIO_InitStruct.Pin = GPIO_PIN_12; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; //!!! GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); GPIO_InitStruct.Pin = GPIO_PIN_2; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; //!!! включить подтяжки! GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF12_SDIO1; HAL_GPIO_Init(GPIOD, &GPIO_InitStruct); /* USER CODE BEGIN SDMMC1_MspInit 1 */ /* USER CODE END SDMMC1_MspInit 1 */ } } Иллюстрации ниже (подсоединение, втулки и SD-карты, которые успешно работают): Пробовал в High Speed Mode наскоряк переключить - не работает. Включал путём установки: #define USE_SD_TRANSCEIVER 1
  9. STM32H743 и SDIO

    Удалось запустить SD карту SD HC 10-й класс скорости + 1-й класс в терминологии UHS-I . Емкостью 16 ГБ. Сектора стали нормально читаться после как на линию CLK повешал ферритовую втулку (с провода питания ноутбука - длина суть больше 1 см). Без ферритовой втулки даёт CRC-ERROR и битые данные. Остальные карты с 2 и 4 ГБ не работают даже с втулкой. Карта подключена к отладке Nucleo-H743 проводами длиной около 15 см. Надо будет попробовать укоротить насколько возможно. Питание на карту беру от встроенного на плате LDO 3,3V. Между питанием и землёй карты - тантал 10 мкФ + керамика 0.1 мкФ.
  10. STM32H743 и SDIO

    Не переживайте. Скорее всего Хал/Куб что-то не учли, и проблема решается вставкой ворк-эраунда. На 407-м тоже пришлось копаться несколько дней(закончилось скачиванием обновленной библиотеки с фиксом). Приложил результат - слева правильное чтение сектора на ПК, справа - не верное чтение (пропуск символов, не те)- на STM32H743:
  11. STM32H743 и SDIO

    Подсоединил DS карту к STM32H743(отладка Nucleo) к SDIO1. Сгенерировал Кубом Хал и вперёд. Читаю нулевой сектор SD карты, который я видел и сравниваю с заранее правильно считанным эталоном побайтно. Сравнение показывает разный результат. Выводил содержимое 0-го сектора на дисплей: часть байтов пропускается или не те, что нужно. Режим без ДМА. Отключал кеширование, выравнивал буфер данных на 512 байт - ничего не помогло. Удалось обнаружить, что функция чтения HAL_SD_ReadBlocks(SD_HandleTypeDef *hsd, uint8_t *pData, uint32_t BlockAdd, uint32_t NumberOfBlocks, uint32_t Timeout) возвращает всегда: HAL_SD_ERROR_DATA_CRC_FAIL Эррата на H743 даёт мутное описание, что-то связанное с линией данных 2 (Wrong data line 2 generation between two blocks  during DDR transfer with Read wait mode enabled) Но раскурить не удалось. Клок тоже понижал , ставил делитель до 256 - не помогает. Поддтяжки к питанию (PULL UP) всех линий включены. Пробовал 3 карты: 2 ,4 и 16 ГБ - со всеми тремя фигня. На STM32H407 с SDIO все карты работают. В чем может быть проблема?
  12. Ой, да ладно! :rolleyes: :biggrin: Мечтать оно не вредно, но реалии намного скромнее. В HAL идёт обращение к NAND как к регистрам: выставляем байты адреса(Addr section), байт команды(Cmd section), затем только читем/пишем(Data section). Нет тут обращения как к массиву даже и близко: HAL_NAND_Read_Page_8b(...) { //........ //Записывается адрес в несколько байт *(__IO uint8_t *)((uint32_t)(deviceAddress | ADDR_AREA)) = 0x00; __DSB(); *(__IO uint8_t *)((uint32_t)(deviceAddress | ADDR_AREA)) = ADDR_1ST_CYCLE(nandAddress); __DSB(); *(__IO uint8_t *)((uint32_t)(deviceAddress | ADDR_AREA)) = ADDR_2ND_CYCLE(nandAddress); __DSB(); //далее ждем....... //Read Page CMD *(__IO uint8_t *)((uint32_t)(deviceAddress | CMD_AREA)) = ((uint8_t)0x00U); __DSB(); //Читаем данные for(; index < size; index++) { *(uint8_t *)pBuffer++ = *(uint8_t *)deviceAddress; } //.............. } У меня делается обращение к дисплею всего 2 записями (CMD_AREA - это A16. =0 - регистр, =1 - данные.): *(__IO uint16_t *)((uint32_t)(deviceAddress )) = ((uint16_t)LCD_REGISTER_N); *(__IO uint16_t *)((uint32_t)(deviceAddress| CMD_AREA )) = ((uint16_t)LCD_DATA); Принцип тот же. А вы предлагаете сделать так (полагая, что если записать смещение в адрес, то оно упадёт на шину): *(__IO uint16_t *)((uint32_t)(deviceAddress | ADDR_AREA | LCD_REGISTER_N)) = ((uint16_t)LCD_DATA); Но этого не будет. Потому что либо товарищ AVI-crak никогда не работал с FMC в режиме NAND, либо он - циничный тролль и издевается надо мной. В мануале на H743 чётко прописан алгоритм взаимодействия FMC c NAND-flash. Что адрес выставляется записью значения в регистр, а не идёт в смещение относительно базы: AVI-crak, Вы бы Бога побоялись что-ли... Ну нельзя ж так издеваться! :05: И перестаньте вводить в заблуждение! ;)
  13. Скажу по секрету, с USB на микроконтроллерах никогда не работал. Только на компе и только через FT232/245. :biggrin: C v3s вопрос о памяти снимается автоматически - 64 biultin :) А на отладках с A13 что есть там уже напаяна DDR. (Olinuxino и SOM) На счёт дисплеев. Пересмотрел все даташиты все LCD, которые использовал и оказалось, что у них всех HOLD после DATA SETUP от 0 до 7 нс. Становится понятным, почему ранее при подключении их к FMC проблем не было. Попался дисплей с обалденно хорошим качеством картинки с SE K800i оригинал (контроллер Toshiba). Но у него HOLD от 15 нс, что нереализуемо на частотах FMC выше 66 Мгц. Пришлось FMC в режим NAND загонять, чтобы выставить нужный HOLD без снижения тактовой частоты FMC (иначе остальные времянки прийдётся загрублять в большую сторону). Но до того как это понял и докопаться до сути - понаставил костыли: 1) Резистор около 2 кОм на !CS 2) Постоянно посыл команды Write Data , перед отправкой фреймбуфера 3) Костыль в алгоритме инициализации Теперь все костыли ушли в небытиё! Дисплей стабильно работает и рисует непрерывно кадр через DMA бе опорных команд (позиция по X,Y; write data) и ничего не съезжает. FMC в режиме NAND рулит! :rolleyes: Правда, на смежном форуме меня пытались убедить, что через NAND мол, можно к дисплею обращаться как к массиву. Но в STM32 адрес NAND Flash задаётся через запись в регистр, также как и данные. Так что смещения относительно базового адреса NAND не вышло. А было бы очень изящно: все регистры дисплея - элементы массива(или структуры), вместо раздельных посылок: адреса и данных.
  14. Олвиннер пока отложил временно, не успеваю. Но один момент успел не понравиться. Я раскопал это в Linux BSP. Работа с TCON в режиме i8080: s32 tcon0_cpu_wr_24b_data(u32 sel, u32 data) { u32 count = 0; while((tcon0_cpu_busy(sel)) && (count < 50)) { count ++; disp_delay_us(100); } lcd_dev[sel]->tcon0_cpu_ctl.bits.ca = 1; //tcon0_cpu_if_reg_t lcd_dev[sel]->tcon0_cpu_wr.bits.data_wr = data; //tcon0_cpu_wr_reg_t return 0; } Видите костыль? Вот он: Меня как аппаратчика, разочаровывают эти строки. Пока временно отложил. Ну и в связи с последними событиями - появление STM на 400 МГц занялся пока изучением Cortex-M7.
  15. Успешно запустил контроллер NAND Flash и прикрутил к нему проблемный дисплей. Получил ещё одно подтверждение того, что дисплей хочет длинный HOLD. Частота FMC=200 МГц. 1 CLK = 5 нс. Первым делом, настроил MPU, для отключения кеширования диапазона адресов: 0x80000000...0x8FFFFFFF (256 МБ). Позже объясню, зачем так много. static void MPU_Conf(void) { MPU_Region_InitTypeDef MPU_InitStruct; HAL_MPU_Disable(); MPU_InitStruct.Enable=MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x80000000; MPU_InitStruct.Size = MPU_REGION_SIZE_256MB; //0x80000000..0x8FFFFFFF MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS; MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0; MPU_InitStruct.IsCacheable=MPU_ACCESS_NOT_CACHEABLE; //NOT CACHEABLE MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsShareable=MPU_ACCESS_SHAREABLE; MPU_InitStruct.Number=MPU_REGION_NUMBER0; MPU_InitStruct.SubRegionDisable=0x00; MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_DISABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } Затем проинитил FMC , NAND. Здесь разные времянки для PMEM и PATT - использую первую для записи, вторую для чтения в регистры LCD (времянки на чтение всегда более длинные): static void MX_FMC_Init(void) { FMC_NAND_PCC_TimingTypeDef ComSpaceTiming; FMC_NAND_PCC_TimingTypeDef AttSpaceTiming; /** Perform the NAND1 memory initialization sequence */ hnand1.Instance = FMC_NAND_DEVICE; /* hnand1.Init */ hnand1.Init.NandBank = FMC_NAND_BANK3; hnand1.Init.Waitfeature = FMC_NAND_WAIT_FEATURE_DISABLE; hnand1.Init.MemoryDataWidth = FMC_NAND_MEM_BUS_WIDTH_8; hnand1.Init.EccComputation = FMC_NAND_ECC_DISABLE; hnand1.Init.ECCPageSize = FMC_NAND_ECC_PAGE_SIZE_256BYTE; hnand1.Init.TCLRSetupTime = 0; hnand1.Init.TARSetupTime = 0; /* hnand1.Config */ hnand1.Config.PageSize = 262144; //256kB >= 320x240x2 hnand1.Config.SpareAreaSize = 262144; //256kB >= 320x240x2 hnand1.Config.BlockSize = 1; hnand1.Config.BlockNbr = 1; hnand1.Config.PlaneNbr = 1; hnand1.Config.PlaneSize = 1; hnand1.Config.ExtraCommandEnable = ENABLE; //Адреса для записи: /* ComSpaceTiming: 0x80000000..0x83FFFFFF */ ComSpaceTiming.SetupTime = 0; //+1 1CLK = 5ns >= 4ns ComSpaceTiming.WaitSetupTime = 3; //+1 4CLK = 20ns >= 18ns 1CLK уже мало ComSpaceTiming.HoldSetupTime = 3; //+0 3CLK = 15ns >= 15ns 1CLK уже мало ComSpaceTiming.HiZSetupTime = 1; //+0 1CLK = 5ns (tSET=tHIZ) >= 4ns 0CLK работает (0CLK: данные появятся сразу после падения NCE, 1CLK: после падения NWE, >1CLK: ещё позже) //Адреса для чтения: /* AttSpaceTiming: 0x88000000..0x8BFFFFFF */ AttSpaceTiming.SetupTime = 254; //+1 AttSpaceTiming.WaitSetupTime = 254; //+1 AttSpaceTiming.HoldSetupTime = 254; //WR:+0 RD:+1 AttSpaceTiming.HiZSetupTime = 254; //+0 if (HAL_NAND_Init(&hnand1, &ComSpaceTiming, &AttSpaceTiming) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } Почитал референс-мануал на H743, внимательно расставил параметры времянок с учётом того, что к некоторым добавляется +1 CLK. ComSpaceTiming.SetupTime = 0; //+1 1CLK = 5ns >= 4ns ComSpaceTiming.WaitSetupTime = 3; //+1 4CLK = 20ns >= 18ns 1CLK уже мало ComSpaceTiming.HoldSetupTime = 3; //+0 3CLK = 15ns >= 15ns 1CLK уже мало ComSpaceTiming.HiZSetupTime = 1; //+0 1CLK = 5ns (tSET=tHIZ) >= 4ns 0CLK работает (0CLK: данные появятся сразу после падения NCE, 1CLK: после падения NWE, >1CLK: ещё позже) Всё согласно времянкам проблемного дисплея: Уточнения: 1) tHIZ выбрано равным tSETUP. Чтобы данные выкидывались на шину сразу же после падения строба записи NWE. Можно сделать вообще tHIZ=0, тогда данные будут выдаваться сразу же после падения NCE - проверил: тоже работает! 2) Если tWAIT меньше 2, то кадр в дисплее начинает перекручиваться и периодически переставлять байты цвета (идут пропуски байтов) 3) Если tHOLD меньше 2, то дисплей повисает. Как раз тот случай, что с NOR/PSRAM контроллером - tHOLD там всегда 1 CLK ! 4) Если tWAIT=2 и tHOLD=2, то дисплей работает, но очень редко зависает (времянка не соответствует приведённой в даташите на LCD). Код что выше, обеспечивает необходимую времянку. Дисплей проработал 1.5 часа без сбоя. Дальше не тестировал. Порты для записи в LCD: #define LCD_WR_COM16 (*(volatile unsigned short int*) 0x80000000) #define LCD_WR_DAT16 (*(volatile unsigned short int*) 0x80010000) Для чтения: #define LCD_RD_COM16 (*(volatile unsigned short int*) 0x88000000) #define LCD_RD_DAT16 (*(volatile unsigned short int*) 0x88010000) Итоговая скорость записи в дисплей: 200MHz/(1+4+3)=25 MHz Соединение дисплея с FMC:
  16. Привожу времянки на проблемный дисплей. Из рисунка видно, что данные защёлкиваются по фронту сигнала !WR. И что важно после этого выдержать tAH=15ns, tDHW=15ns: А теперь в референс-мануале смотрим главу FMC и находим времянки. Времянка номер 1 - Mode A, цикл записи: И видим - всего 1 CLK FMC на tAH, tDHW ! :crying: Что при тактовой FMC 200 MHZ даст всего 5 нс. Глянул времянки других дисплеев: у них tAH варьируется от 2 до 7 нс, поэтому с ними проблем не возникало (хотя работают на пределе своих возможностей). В том же референс-мануале - другая времянка - Mode D, цикл записи: Тут зачем-то Address Hold задвинули перед DATA Setup, а должно быть ПОСЛЕ. Значит, тоже не годится. Из всего резюмирую: для "длинно-хвостной" периферии для выдерживания tAH, tDHW прийдётся снижать тактовую частоту FMC - как единственный путь для получения tAH= 1 CLK FMC. Потому что другого способа не вижу как управлять длительностью холда. Забавно, что после снижения тактовой FMC, резистор в 2 кОм на Chip Select дисплея можно исключить - вместе с ёмкостью вывода он создавал затянутый фронт до- и после- CS, тем самым внося задержку, которой так не хватало. О резисторе писал ранее здесь: https://electronix.ru/forum/index.php?showt...147646&st=0 Планирую попробовать подключить дисплей к NAND контроллеру. У него можно регулировать "хвост" после DATASETUP (HOLD): О результатах напишу. А вообще конечно, STM-овцы облажались с FMC. :biggrin: Даже на вшивых AVR-ках у XMEM была возможность регулировать tAH:
  17. Обнаружил интересную проблему и способ её решения. Отладочная плата Nucleo-H743. Процессор STM32H743. Частота ядра 400 МГц. Частота шины FMC выставлена 200 МГц (максимум). Тактирование заведено от HCLK3. На FMC висит дисплей с настроенными времянками. Инит дисплея проходит успешно, его ID производителя успешно определяется. Далее в дисплей начинаю сыпать, сыпать, сыпать данные.... Через DMA. Только данные. Ножка A16 всегда =1 при этом. Возникает проблема: дисплей перестаёт отображать данные. Либо он "зависает" (картинка не обновляется), либо он уходит в стэндбай - и весь экран становится белым. При этом процессор и остальная периферия работают. И с каждым сбросом CPU проблема повторяется. Но стоило выбрать другой источник тактирования FMC - PLL1Q, а частоту тактирования FMC сделать в 2 раза ниже: 100 МГц, дисплей работает как часы и передача данных не срывается. Времянки при этом перерасчитаны (тоесть в масштабах времени они одинаковы, меняется число клоков) - использую Mode A - там только Address Setup и Data Setup. Пробовал сильно укорачивать времянки - всёравно работает. Картинка не перекручивается - пиксели не пропускаются, и нужного цвета. Но стоит поднять частоту FMC чуть выше 100 МГц, то проблема снова появляется, даже если времянки поставить очень длинные. Я вот о чем подумал - в Mode A у FMC есть "хвостик" после Data Setup - его длина ВСЕГДА ФИКСИРОВАНА и равна 1 такту шины FMC. Картинка ниже. Вопрос вот в чём, насколько существенна длительность этого "хвоста" для работы с периферией на FMC? Ведь по сути нет никаких способов влиять программно на этот "хвост", кроме как занижать частоту FMC. А значит стабильную работу с данным LCD можно получить только, выставив минимально допустимую длину "хвоста", понизив частоту FMC и выставив остальные параметры времянок. Пробовал другие дисплеи(модели другие!) подключать, таких проблем не было. Только один конкретный дисплей так ведёт себя. В чем может быть ещё проблема? Дисплеи на "макаронах" до 10 см., это не критично для обмена на частоте данных 20-30 МГц.
  18. Дело в том что у SEGA MegDrive, о которй Вы тут написали видеоконтроллер поддерживает разрешение до 320x240 пикселей. И в QVGA LCD, который я применяю, оно очень вписывается. Тут фильтры НЕ нужны и не используются. То же касается NES и SNES (256x240 , 256x256). Но в Atari Lynx экран всего 160x102, в ГеймБой: 160x144. На QVGA-шном дисплее это всего 1/4 площади. Картинка маленькая, неудобно смотреть (особенно когда нужно в формактор кредитки уложить все устройство). И если с бордюрами в NES,SNES ещё как-то можно смириться, то тут стретч 2x как бы и напрашивается автоматически.
  19. Цель - прощупать новый флагман от STM: Cortex-M7 @ 400MHz H743 в мультимедийном контексте. Just for fun & Proof concept. Если подробнее, то веду тему здесь (там же демонстрация работы, исходники и многое другое): http://vrtp.ru/index.php?showtopic=30174&st=0 Эмуляторы игровых приставок/консолей Все фильтры, которые тут обсуждались успешно применил (HQ2x в стадии отладки и оптимизации) :rolleyes:
  20. Попробовал вручную оптимизировать ASM-листинг с GCC и потом его в объектник с помощью ассемблера. Что заметил: 1) Много лишних переприсавиваний (верхние 2 строки закомментировал, ниже свой вариант): @ ldr r3, [r8, r2, lsl #2] @ mov ip, r3 ldr ip, [r8, r2, lsl #2] .syntax unified @ 128 "HQ2x.cpp" 1 usub8 r3, lr, ip usub8 ip, r5, r3 sel ip, ip, r3 usub8 ip, r7, ip sel ip, r5, r7 Причем избавиться от этого не вышло, манипулируя разными комбинациями в объявлении входных/выходных/clobber- переменных 2) Цикл, переходы на метки - всё разворачивает. Объявление переменной границы цикла как volatile не даёт развернуть цикл, и он работает медленее, чем когда развёрнуто. Для моих целей оказался лучше другой фильтр - SaI. Он лучше сглаживает края (антиалиасинг), чем HQ2x и LQ2x. Исходники SaI фильтра + makefile + бинарник под Win32: SaI2x_Win32.rar Входные данные: test.raw 160x144 RGB 8:8:8 Выходные: test2x.raw 288x320 RGB 8:8:8 (разворот на 90 градусов!) Картинка, иллюстрирующая работу фильтров: BSpline - это "обычный фотошопный" фильтр (изображение размыто) SaI 320x240 - попытка втиснуть 320x288 в дисплей 320x240. Каждая 6-я строка выходного буфера пропускается, получается 240 линий вместо 288. Вроде б неплохо, если сравнивать с 320x240. И что самое главное, алгоритм менее ресурсозатратный , чем HQ2x : нет переходов и считываний из лукапов :)
  21. STM32H743 MDMA

    Спасибо за развёрнутый ответ! :rolleyes:
  22. STM32H743 MDMA

    Теперь всё ясно. Всем спасибо. Интересно, что когда программировал DMA звуковой карты на ПК, там не нужно было оперировать с кешем вообще. Хотя в CPU были включены кеши. Немного огорчило, что максимальный блок для передачи MDMA - 64 кБ. Пришлось буфер LCD резать на кусочки. Сделал 3 куска (320x240x2 /3 <64kB). Всё работает. Свопинг байтов тоже сделан, что и нужно было! u16 Buffer[240*320] __attribute__((aligned(32))); int main(void) { SCB_EnableICache(); SCB_EnableDCache(); HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_FMC_Init(); MX_DMA_Init(); MX_MDMA_Init(); LED(RESET); LCD_Reset(); LCD_Init(); LCD_Position(0,0,W-1,H-1); for(u32 i=0;i<(240*320);i++) { u32 c=i/(240*40); Buffer[i]= (((c/4)*0x1F)<<11) | ((((c/2)&1)*0x3F)<<5) | ((c&1)*0x1F); } SCB_CleanDCache(); if(HAL_MDMA_Start(&hmdma_mdma_channel7_sw_0,(u32)Buffer,(u32)&LCD_DAT32,(240*320*2)/3,3)!=HAL_OK)while(1); if(HAL_MDMA_PollForTransfer(&hmdma_mdma_channel7_sw_0,HAL_MDMA_FULL_TRANSFER,1000)!=HAL_OK)while(1); // SCB_InvalidateDCache(); while(1) { LED(SET); delay_ms(100); LED(RESET); delay_ms(100); } Инит МДМА: 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(); } } А для чего бурсты в DMA ? Они ускорят обмен с LCD?
  23. STM32H743 MDMA

    Всё заработало, когда включил MPU. Протестил на разной памяти - вот что вышло: 1) С выключенным DCache работают все комбинации С включенным DCache: 2) DTCM => DTCM - работает без включения MPU 3) любой регион RAM => DTCM - работает без включения MPU 4) любой регион RAM => любой регион RAM кроме DTCM - требует включения MPU на адрес приёмника. static void MPU_Conf(void) { MPU_Region_InitTypeDef MPU_InitStruct; HAL_MPU_Disable(); MPU_InitStruct.Enable=MPU_REGION_ENABLE; MPU_InitStruct.BaseAddress = 0x30040000; MPU_InitStruct.Size = MPU_REGION_SIZE_32KB; MPU_InitStruct.AccessPermission=MPU_REGION_FULL_ACCESS; MPU_InitStruct.TypeExtField=MPU_TEX_LEVEL0; MPU_InitStruct.IsCacheable=MPU_ACCESS_CACHEABLE; MPU_InitStruct.IsBufferable=MPU_ACCESS_BUFFERABLE; MPU_InitStruct.IsShareable=MPU_ACCESS_SHAREABLE; MPU_InitStruct.Number=MPU_REGION_NUMBER0; MPU_InitStruct.SubRegionDisable=0x00; MPU_InitStruct.DisableExec=MPU_INSTRUCTION_ACCESS_DISABLE; HAL_MPU_ConfigRegion(&MPU_InitStruct); HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT); } Попробую Вашу идею. Так invalidate D-cache надо вызывать после приёма любого DMA (DMA, MDMA, DMA2D) ? Или это касается только MDMA? SCB_InvalidateDCache(); - сделал, тоже заработало и без включения MPU! Спасибо! :yeah: По чему в случае "обычного" DMA работает без SCB_InvalidateDCache(); ? или это специфика только MDMA? Всё, понял. Это для приёмной памяти. В случае с LCD Invalidate DCache делать не нужно (его адреса портов не кешированы). Потому работало на обычном DMA. С памятью на приёме обязателен Invalidate DC.
  24. STM32H743 MDMA

    Написал тестовый пример, пересылка память-память через MDMA. Инит МДМА: static void MX_MDMA_Init(void) { /* MDMA controller clock enable */ __HAL_RCC_MDMA_CLK_ENABLE(); /* 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_BLOCK_TRANSFER; hmdma_mdma_channel7_sw_0.Init.Priority = MDMA_PRIORITY_LOW; hmdma_mdma_channel7_sw_0.Init.Endianness = MDMA_LITTLE_ENDIANNESS_PRESERVE; hmdma_mdma_channel7_sw_0.Init.SourceInc = MDMA_SRC_INC_BYTE; //HALFWORD; hmdma_mdma_channel7_sw_0.Init.DestinationInc = MDMA_DEST_INC_BYTE; //HALFWORD; hmdma_mdma_channel7_sw_0.Init.SourceDataSize = MDMA_SRC_DATASIZE_BYTE; //HALFWORD; hmdma_mdma_channel7_sw_0.Init.DestDataSize = MDMA_DEST_DATASIZE_BYTE; //HALFWORD; hmdma_mdma_channel7_sw_0.Init.DataAlignment = MDMA_DATAALIGN_PACKENABLE; hmdma_mdma_channel7_sw_0.Init.BufferTransferLength = 8; //32; //1; 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(); } } Main: u8 Buffer0[32] __attribute__((at(0x30000000))); //__attribute__((aligned(32))); volatile u8 Buffer1[32] /*__attribute__((aligned(32)));*/ __attribute__((at(0x30040000))); //__attribute__((aligned(32))); int main(void) { SCB_EnableICache(); SCB_EnableDCache(); HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); MX_MDMA_Init(); LED(RESET); memset( Buffer0,0,sizeof(Buffer0)); memset((void*)Buffer1,0,sizeof(Buffer1)); for(u32 i=0;i<32;i++)Buffer0[i]=0xAA; SCB_CleanDCache(); //сбрасываем содержимое кэша данных в память if(HAL_MDMA_Start(&hmdma_mdma_channel7_sw_0,(u32)Buffer0,(u32)Buffer1,1,1) !=HAL_OK)while(1); if(HAL_MDMA_PollForTransfer(&hmdma_mdma_channel7_sw_0,HAL_MDMA_BLOCK_TRANSFER,1000)!=HAL_OK)while(1); delay_ms(500); if(Buffer1[0]!=0xAA) { LED(SET); while(1); } while(1) { LED(SET); delay_ms(100); LED(RESET); delay_ms(100); } while(1); Старт и опрос проходят без проблем. Проверяю первый байт приёмного буфера Buffer1, он не равен 0xAA как это в источнике - светодиод загорается и горит вечно: if(Buffer1[0]!=0xAA) { LED(SET); while(1); } Что не здесь так?
  25. У процессоров Intel x86 в защищённом режиме можно настроить дескрипторы так, чтобы из региона, где выполняется код чтение данных было запрещено. На то он дескриптор кода. У STM32F7 также, не?