Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: STM342F4 и FSMC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > ARM
__inline__
Использую отладочную плату STM32F4Discovery (контроллер STM32F407) и LCD, подключенный по FSMC (дисплей от телефона Sony Ericsson K800i).

Обмен данными с дисплеем идёт нормально до частоты процессора 112 МГц.

Стоит поднять частоту до 168 МГц - при записи в видеопамять дисплея возникают сбои: неправильная запись данных или декодирует их как команды (при этом дисплею окончательно сносит крышу). Пробовал выставлять разные Address_Setup, Data_Setup - не помогло.

Обнаружил, если снизить частоту тактирования на линию порта GPIO D7 - это !CS LCD до 2 МГц, или подсоединить этот вывод через резистор 820 Ом (с меньшими значениями не игрался), то всё работает корректно. Причём, дисплей заводится на сверх-быстрых времянках!

В принципиальной схеме на телефон на каждой линии "дисплей-процессор" стоит конденсатор 33 пФ на землю.

Дисплей соединён с отладочной платой "макаронами" длиной 10 см. На шине больше ничего кроме дисплея нет.

Какие причины столь странного поведения? От чего без резистора на линии !CS дисплей глючит?

Код настройки GPIO и FSMC ниже(работает):

CODE
void GPIO(void)
{
GPIO_InitTypeDef gpio;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_
GPIOE,ENABLE);

//LCD
GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC); // D0
GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC); // D1
GPIO_PinAFConfig(GPIOD,GPIO_PinSource0 ,GPIO_AF_FSMC); // D2
GPIO_PinAFConfig(GPIOD,GPIO_PinSource1 ,GPIO_AF_FSMC); // D3
GPIO_PinAFConfig(GPIOE,GPIO_PinSource7 ,GPIO_AF_FSMC); // D4
GPIO_PinAFConfig(GPIOE,GPIO_PinSource8 ,GPIO_AF_FSMC); // D5
GPIO_PinAFConfig(GPIOE,GPIO_PinSource9 ,GPIO_AF_FSMC); // D6
GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC); // D7
GPIO_PinAFConfig(GPIOD,GPIO_PinSource11,GPIO_AF_FSMC); //A16 => RS
GPIO_PinAFConfig(GPIOD,GPIO_PinSource7 ,GPIO_AF_FSMC); //NE1 => CS !!! ВОСПРИИМЧИВ К ПОМЕХАМ !!! РЕЗИСТОР ИЛИ ПОНИЗИТЬ ЧАСТОТУ GPIO D7
GPIO_PinAFConfig(GPIOD,GPIO_PinSource4 ,GPIO_AF_FSMC); //NOE => RD
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5 ,GPIO_AF_FSMC); //NWE => WR

gpio.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_11
|GPIO_Pin_14|GPIO_Pin_15;
gpio.GPIO_Mode=GPIO_Mode_AF;
gpio.GPIO_Speed=GPIO_Speed_100MHz;
gpio.GPIO_OType=GPIO_OType_PP;
gpio.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD,&gpio);

gpio.GPIO_Pin=GPIO_Pin_7|GPIO_Pin_8|GPIO_Pin_9|GPIO_Pin_10;
gpio.GPIO_Mode=GPIO_Mode_AF;
gpio.GPIO_Speed=GPIO_Speed_100MHz;
gpio.GPIO_OType=GPIO_OType_PP;
gpio.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOE,&gpio);

//LCD !RST B11
gpio.GPIO_Pin=GPIO_Pin_11;
gpio.GPIO_Mode=GPIO_Mode_OUT;
gpio.GPIO_Speed=GPIO_Speed_2MHz;
gpio.GPIO_OType=GPIO_OType_PP;
gpio.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB,&gpio);

//LCD WSYNC B3
gpio.GPIO_Pin=GPIO_Pin_3;
gpio.GPIO_Mode=GPIO_Mode_IN;
gpio.GPIO_Speed=GPIO_Speed_2MHz;
gpio.GPIO_OType=GPIO_OType_PP;
gpio.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOB,&gpio);

//LED TEST D12
gpio.GPIO_Pin=GPIO_Pin_12;
gpio.GPIO_Mode=GPIO_Mode_OUT;
gpio.GPIO_Speed=GPIO_Speed_2MHz;
gpio.GPIO_OType=GPIO_OType_PP;
gpio.GPIO_PuPd=GPIO_PuPd_NOPULL;
GPIO_Init(GPIOD,&gpio);
}

void FSMC(void) //!!! HCLK=168 MHz
{
FSMC_NORSRAMTimingInitTypeDef fsmcTimingRead,fsmcTimingWrite;
FSMC_NORSRAMInitTypeDef fsmc;

RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);

fsmcTimingRead.FSMC_AddressSetupTime=1; //!!!
fsmcTimingRead.FSMC_AddressHoldTime=0;

fsmcTimingRead.FSMC_DataSetupTime=13; //RD

fsmcTimingRead.FSMC_BusTurnAroundDuration=0;
fsmcTimingRead.FSMC_CLKDivision=0;
fsmcTimingRead.FSMC_DataLatency=0;
fsmcTimingRead.FSMC_AccessMode=FSMC_AccessMode_A;

memcpy(&fsmcTimingWrite,&fsmcTimingRead,sizeof(fsmcTimingRead));

fsmcTimingWrite.FSMC_DataSetupTime=2; //WR

fsmc.FSMC_Bank=FSMC_Bank1_NORSRAM1;
fsmc.FSMC_DataAddressMux=FSMC_DataAddressMux_Disable;
fsmc.FSMC_MemoryType=FSMC_MemoryType_SRAM;
fsmc.FSMC_MemoryDataWidth=FSMC_MemoryDataWidth_8b;
fsmc.FSMC_BurstAccessMode=FSMC_BurstAccessMode_Disable;
fsmc.FSMC_WaitSignalPolarity=FSMC_WaitSignalPolarity_Low;
fsmc.FSMC_WrapMode=FSMC_WrapMode_Disable;
fsmc.FSMC_WaitSignalActive=FSMC_WaitSignalActive_BeforeWaitState;
fsmc.FSMC_WriteOperation=FSMC_WriteOperation_Enable;
fsmc.FSMC_WaitSignal=FSMC_WaitSignal_Disable;
fsmc.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
fsmc.FSMC_ExtendedMode=FSMC_ExtendedMode_Enable; //For Different Read & Write Timings !!!
fsmc.FSMC_WriteBurst=FSMC_WriteBurst_Disable;

fsmc.FSMC_ReadWriteTimingStruct=&fsmcTimingRead;
fsmc.FSMC_WriteTimingStruct=&fsmcTimingWrite;

FSMC_NORSRAMInit(&fsmc);
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1,ENABLE);
}
ViKo
Глючит от отражений в линии. Спасают резисторы последовательно с выходами МК, пара десятков омов. А конденсаторы выкинуть, это ненаучно.
k155la3
Надо посмотреть по док. на дисплей, выдерживаются ли таймауты от ~CS до-после RD WR.
Для скоростных интерфейсов сигнальные линии в кабеле должны чередоваться с "обратным" GND (как данные так и управление).
И линии передачи должны быть согласованы (выше, ViKo). Кабель может обернут фольгой-экраном.
(длина кабеля на Вашем девайсе уже "ощутимая"). Со стороны процессора должы работать push-pull выходы.
В телефоне стоят конденсаторы, тк (возможно) скорость интерфейса меньше, а есть сильный уровнеь помех от радиоизлучения евойного.



__inline__
Цитата(ViKo @ Jun 27 2018, 09:03) *
Глючит от отражений в линии. Спасают резисторы последовательно с выходами МК, пара десятков омов. А конденсаторы выкинуть, это ненаучно.

Провел эксперименты:

1) Заменил резистор на 22 Ом, припаял близко к ноге Discovery, насколько возможно. Не работает.
2) 47 Ом - Не работает
3) 300 Ом - Не работает

4) 600 Ом - заработало.

На всякий случай скажу, многократно прозванивал все соединения - на предмет контактов(всё ОК), на предмет замыканий с соседними (тоже всё Ок).

Цитата(k155la3 @ Jun 27 2018, 09:54) *
Надо посмотреть по док. на дисплей, выдерживаются ли таймауты от ~CS до-после RD WR.


Ставил самую медленную времянку при HCLK=168 МГц:

smcTimingRead.FSMC_AddressSetupTime=15
fsmcTimingRead.FSMC_AddressHoldTime=15;
fsmcTimingRead.FSMC_DataSetupTime=255;
fsmcTimingRead.FSMC_BusTurnAroundDuration=15;
fsmcTimingRead.FSMC_CLKDivision=15;
fsmcTimingRead.FSMC_DataLatency=15;
fsmcTimingRead.FSMC_AccessMode=FSMC_AccessMode_A;
fsmcTimingWrite.FSMC_DataSetupTime=255;

Всё равно, без снижения тактовой частоты до 112 МГц (=HCLK) без резистора не работает.
Или если на линию GPIO CS выставить 2 МГц, а не 100 - тогда без резистора работает.


Кстати, всегда мучал вопрос, что такое GPIO_Speed_100MHz ? Как оно реализовано в STM32F407 ? Это синхронный такт для пина или фильтр подавления глитчей?

Цитата(k155la3 @ Jun 27 2018, 09:54) *
Для скоростных интерфейсов сигнальные линии в кабеле должны чередоваться с "обратным" GND (как данные так и управление).

В этой модели дисплея не чередуются с GND.
Вот в LCD от SE W580, S500 чередуются - почти через каждые 2-3 линии идет ножка с GND.

Цитата(k155la3 @ Jun 27 2018, 09:54) *
Кабель может обернут фольгой-экраном.

Это надо сделать или вы про причину глюка? У меня провода не экранировны (обычные Ардуиновские макароны)

Цитата(k155la3 @ Jun 27 2018, 09:54) *
Со стороны процессора должы работать push-pull выходы.


Так и есть, подтяжки и open drain не включены. Код инита GPIO, FSMC привел в первом сообщении.
ViKo
Тогда нужно нарисовать на бумаге временную диаграмму обмена по шине и задать правильно Address_setup, Address_hold, Data_duration.
Цитата
Заменил резистор на 22 Ом, припаял близко к ноге Discovery, насколько возможно. Не работает.

О-ля-ля... так от ноги МК до ноги Дискавери уже несколько сантиметров.
Цитата
Кстати, всегда мучал вопрос, что такое GPIO_Speed_100MHz ? Как оно реализовано в STM32F407 ? Это синхронный такт для пина или фильтр подавления глитчей?

Задает ток в момент переключения выхода, а потом возвращается к стандартному. Чтобы перезарядить емкость подключенной к порту цепи. Малая скорость задает малый ток, заваленный фронт, отражения не проявляются так заметно.
__inline__
Цитата(ViKo @ Jun 27 2018, 13:20) *
Тогда нужно нарисовать на бумаге временную диаграмму обмена по шине и задать правильно Address_setup, Address_hold, Data_duration.

Ещё интересный вопрос возник по сигналам FSMC.
Допустим мы настроили FSMC в режиме 8 бит (дисплей).
Общение идёт через 2 порта:
Код
#define LCD_COM16 (*(volatile unsigned short int*) 0x60000000)
#define LCD_DAT16 (*(volatile unsigned short int*) 0x60010000)

Несмотря на 8 битную шину, я объявил их 16-битными. Потому что контроллер дисплея просит 16-битные команды, а делать 2 раза по 8 не хочется(как это делают обычно: шлют старший, затем младший байты. Обнаружил, что можно полу-слово отправить, развернув байты предварительно, даже если шина физически 8 бит, а не 16)

Как будет FSMC дёргать стробами CS и WR ? После каждого байта или после полу-слова? Адрес при этом будет увеличиваться?

Или 4 байта сразу так: #define LCD_DAT32 (*(volatile unsigned long int*) 0x60010000)
Тоже работает.

Что происходит с CS, WR, A ?
Я полагаю на шине адреса будет инкремент адреса на +1 с каждым байтом, а стробы CS,WR будут дергаться с каждым байтом.
Увеличение адреса нас не трогает, потому что размер банка больше, чем количество слов, которое надо переслать. А дисплею всёравно - у него регистр видеопамяти один, адрес автоинкрементируется внутри него.

Верно или нет?

Верно ли моё предположение, что для быстрой пересылки лучше писать в 32-битный регистр, а не 4 раза по 8 бит в случае если шина 8 битная?
Процессор считает одну инструкцию вместо 4-х получится экономия времени:

Иными словами так быстрее:
Код
void LCD_Transfer(void)
{
register u32 i=(320*240)>>1;
register u32 *v=(u32*)VideoBuffer;
while(i--)LCD_DAT32=rev16(*v++);
}


Чем:

Код
void LCD_Transfer(void)
{
register u32 i=(320*240);
register u16 *v=(u16*)VideoBuffer;
while(i--)LCD_DAT16=rev16(*v++);
}


и тем более чем:

Код
void LCD_Transfer(void)
{
register u32 i=(320*240)<<1;
register u8 *v=(u8*)VideoBuffer;
while(i--)LCD_DAT8=*v++;
}


Правда, прийдётся байты разворачивать.

Или в случае 8-битной шины выигрыша не даст?
ViKo
По моему, шину нужно 8-битовой определить. А посылать можно 16-битовые слова, и контроллер их в 2 этапа передаст. Во всяком случае 16/32 так делается. Дожно быть описано в документации.
__inline__
Цитата(ViKo @ Jun 27 2018, 15:10) *
По моему, шину нужно 8-битовой определить. А посылать можно 16-битовые слова, и контроллер их в 2 этапа передаст. Во всяком случае 16/32 так делается. Дожно быть описано в документации.

Я так и сделал. Всё работает!
Определил шину 8 битовой, но посылаю по 16 бит для команд и и по 32 бит -данные.

Вопрос был в том, насколько 16/32 битные пересылки будут быстрее, чем 8-битные - в случае когда шина физически 8 бит.

И как дергается строб !CS - каждый байт или 1 раз за всю 16/32-битную пересылку?
VladislavS
Цитата(__inline__ @ Jun 28 2018, 03:41) *
И как дергается строб !CS - каждый байт или 1 раз за всю 16/32-битную пересылку?
А вот неизвестно. Может один раз, а может и прервать, если что-то более приоритетное вклинится.
ViKo
Дергается на каждый байт. Как для обычных 8 битовых пересылок.
__inline__
Ещё проделал эксперимент.

Устройство на шине одно, на CS подал логический "0", просто присоединив его к GND. Дисплей не запустился.

Выходит, что STM32 на шину FSMC может давать мусор в моменты когда NE(он же и CS) =1 ? Тоесть самодельный дешифратор генерации CS1, CS2.. CSn на несколько устройств не выйдет?

Хотел на STM32F407 повешать 2 устройства на FSMC, а тут видать облом - только NE1 есть и всё. Остальные NE2-4 только в BGA sad.gif
ViKo
Адресом разделяйте.
VladislavS
Цитата(ViKo @ Jun 28 2018, 08:38) *
Дергается на каждый байт. Как для обычных 8 битовых пересылок.
Если данные успевают поступать, то всё что в пределах одного #CS объединяется под ним. Вот недавно делал. Тут, правда, 16-битные пересылки, но это не меняет сути. Все 10 записей под одним #CS происходят.
CODE
__no_init volatile uint16_t cpld_regs[16] @0x60000000;

extern "C" void EXTI0_IRQHandler()
{
cpld_regs[0] = ppm8s.state.rx.chanel[0].fv_att_h.fvatt;
cpld_regs[1] = ppm8s.state.rx.chanel[0].fv_att_v.fvatt;
cpld_regs[2] = ppm8s.state.rx.chanel[1].fv_att_h.fvatt;;
cpld_regs[3] = ppm8s.state.rx.chanel[1].fv_att_v.fvatt;
cpld_regs[4] = ppm8s.state.rx.chanel[2].fv_att_h.fvatt;;
cpld_regs[5] = ppm8s.state.rx.chanel[2].fv_att_v.fvatt;
cpld_regs[6] = ppm8s.state.rx.chanel[3].fv_att_h.fvatt;;
cpld_regs[7] = ppm8s.state.rx.chanel[3].fv_att_v.fvatt;
cpld_regs[8] = (uint16_t)ppm8s.state.rx.dt_hp;
cpld_regs[9] = (uint16_t)ppm8s.state.rx.dt_vp;
GPIOE->BSRR = (1<<4); //LE_RF_OFF=1
EXTI->PR = EXTI_PR_PR0;
GPIOE->BSRR = (1<<16+4); //LE_RF_OFF=0
}

__inline__
Цитата(VladislavS @ Jun 28 2018, 06:54) *
Если данные успевают поступать, то всё что в пределах одного #CS объединяется под ним. Вот недавно делал. Тут, правда, 16-битные пересылки, но это не меняет сути. Все 10 записей под одним #CS происходят.
CODE
__no_init volatile uint16_t cpld_regs[16] @0x60000000;

extern "C" void EXTI0_IRQHandler()
{
cpld_regs[0] = ppm8s.state.rx.chanel[0].fv_att_h.fvatt;
cpld_regs[1] = ppm8s.state.rx.chanel[0].fv_att_v.fvatt;
cpld_regs[2] = ppm8s.state.rx.chanel[1].fv_att_h.fvatt;;
cpld_regs[3] = ppm8s.state.rx.chanel[1].fv_att_v.fvatt;
cpld_regs[4] = ppm8s.state.rx.chanel[2].fv_att_h.fvatt;;
cpld_regs[5] = ppm8s.state.rx.chanel[2].fv_att_v.fvatt;
cpld_regs[6] = ppm8s.state.rx.chanel[3].fv_att_h.fvatt;;
cpld_regs[7] = ppm8s.state.rx.chanel[3].fv_att_v.fvatt;
cpld_regs[8] = (uint16_t)ppm8s.state.rx.dt_hp;
cpld_regs[9] = (uint16_t)ppm8s.state.rx.dt_vp;
GPIOE->BSRR = (1<<4); //LE_RF_OFF=1
EXTI->PR = EXTI_PR_PR0;
GPIOE->BSRR = (1<<16+4); //LE_RF_OFF=0
}



Скиньте плиз свой инит FSMC, интересно глянуть его на предмет бурстов.
VladislavS
Цитата(__inline__ @ Jun 28 2018, 14:27) *
Скиньте плиз свой инит FSMC, интересно глянуть его на предмет бурстов.

Прошу прощения за магические числа, надо будет переписать... sad.gif
Код
  //Инициализация FMC для доступа к регистрам CPLD
  FMC_Bank1->BCR1 = 0x1091;
  FMC_Bank1->BTR1 = 0x0FFF01F2;


CODE
FMC_BCR1_MBKEN = 1
FMC_BCR1_MUXEN = 0
FMC_BCR1_MTYP = 00 [SRAM]
FMC_BCR1_MWID = 01 [16 бит]
FMC_BCR1_FACCEN = 0
FMC_BCR1_BURSTEN = 0
FMC_BCR1_WAITPOL = 0
FMC_BCR1_WRAPMOD = 0
FMC_BCR1_WAITCFG = 0
FMC_BCR1_WREN = 1
FMC_BCR1_WAITEN = 0
FMC_BCR1_EXTMOD = 0
FMC_BCR1_ASYNCWAIT = 0
FMC_BCR1_CPSIZE = 000
FMC_BCR1_CBURSTRW = 0
FMC_BCR1_CCLKEN =0

FMC_BTR1_ADDSET = 2
FMC_BTR1_ADDHLD = F
FMC_BTR1_DATAST = 1
FMC_BTR1_BUSTURN = F
FMC_BTR1_CLKDIV = F
FMC_BTR1_DATLAT = F
FMC_BTR1_ACCMOD = 0 [A mode]


Ещё раз хочу отметить, что данные должны успевать поступать. В моём случае процессор молотит на 168 МГц и приведённый выше код скомпилирован очень эффективно. Быстрее, наверное, только DMA, и то не уверен. Всё происходит где-то за 250 нс (плюс/минус точно не помню).
CODE
LDR.W R3,??DataTable6_1 ;; 0x40013c14
LDRH R2,[R1, #+0]
MOV R0,#+1610612736
STRH R2,[R0, #+0]
LDRH R2,[R1, #+2]
STRH R2,[R0, #+2]
LDRH R2,[R1, #+4]
STRH R2,[R0, #+4]
LDRH R2,[R1, #+6]
STRH R2,[R0, #+6]
LDRH R2,[R1, #+8]
STRH R2,[R0, #+8]
LDRH R2,[R1, #+10]
STRH R2,[R0, #+10]
LDRH R2,[R1, #+12]
STRH R2,[R0, #+12]
LDRH R2,[R1, #+14]
STRH R2,[R0, #+14]
LDRB R2,[R1, #+16]
STRH R2,[R0, #+16]
MOVS R2,#+1
LDRB R1,[R1, #+17]
STRH R1,[R0, #+18]
MOVS R1,#+16
LDR.W R0,??DataTable6_2 ;; 0x40020c18
STR R1,[R0, #+1024]
MOV R1,#+1048576
STR R1,[R0, #+1024]
STR R2,[R3, #+0]
jcxz
Цитата(VladislavS @ Jun 28 2018, 15:02) *
приведённый выше код скомпилирован очень эффективно.

А зачем LDRH/STRH? Разве 32 бита из STR не будут автоматом распилены на две 16-битные записи контроллером шины?
VladislavS
Цитата(jcxz @ Jun 29 2018, 01:27) *
А зачем LDRH/STRH?

Потому что в С-коде написаны 16-битные пересылки. Компилятор не имел права ослушаться.

Цитата(jcxz @ Jun 29 2018, 01:27) *
Разве 32 бита из STR не будут автоматом распилены на две 16-битные записи контроллером шины?

Будут, конечно. Только в скорости в моём случае уже не выиграть, я упёрся в скорость устройства в которое пишу, а вот читаемость кода пострадает. Режимы работы шины я настраивал с осциллографом под отладчиком. Отсюда и магические числа вылезли - после отладки просто скопировал значение регистров в код.

PS: Да, можно немного сэкономить.
Код
  *(uint32_t *)&cpld_regs[0] = *(uint32_t *)&ppm8s.state.rx.chanel[0];
  *(uint32_t *)&cpld_regs[2] = *(uint32_t *)&ppm8s.state.rx.chanel[1];
  *(uint32_t *)&cpld_regs[4] = *(uint32_t *)&ppm8s.state.rx.chanel[2];
  *(uint32_t *)&cpld_regs[6] = *(uint32_t *)&ppm8s.state.rx.chanel[3];
  cpld_regs[8] = (uint16_t)ppm8s.state.rx.dt_hp;     //Эти поля uint8_t
  cpld_regs[9] = (uint16_t)ppm8s.state.rx.dt_vp;

И получить LDR/STR на части структуры, которая случайно совпала по расположению в памяти с внешними регистрами. Но мне это категорически не нравится, так как структуру теперь менять ни-ни. А если собирать из двух LDRH один STR, то это ещё и проиграешь в результате.

Что потом с этим через N лет кто-то без меня будет делать? biggrin.gif
jcxz
Цитата(VladislavS @ Jun 29 2018, 04:58) *
Но мне это категорически не нравится, так как структуру теперь менять ни-ни. А если собирать из двух LDRH один STR, то это ещё и проиграешь в результате.

Я в таких случаях обычно использую union:
Код
union {
  struct {
    u16 r0, r1, ..., rx;
  } r16;
  struct {
    u32 r0, r1, ..., ry;
  } r32;
};

Первый член (r16) - логическое представление данных внутри; второй (r32) - для 32-битных обращений при пересылке.
Если не нравятся лишние элементы в длинном конечном пути к членам, то можно и без имён r16, r32, просто задав разные имена внутренним членам - современные компиляторы уже нормально понимают безымянные структуры.
Имхо - получается наглядно. Хотя конечно - на вкус и цвет....

Цитата(VladislavS @ Jun 29 2018, 04:58) *
Что потом с этим через N лет кто-то без меня будет делать? biggrin.gif

Всё перепишут на Cortex-Mxxx? laughing.gif
__inline__
Разобрался с быстрым копированием по 128 байт за раз:

ASM:
Код
memcpy128 PROC
                EXPORT memcpy128

      vpush {s16 - s31}                                        ; 17

z     vldm.32 r1!, {s0 - s31}                                  ; 33
      vstm.32 r0!, {s0 - s31}                                  ; 33
      subs.n r2, #1                                            ; 1
      bne.n z                                                  ; ~3 (taken)

      vpop {s16 - s31}                                         ; 17
      bx lr                                                    ; 1-3??

                ENDP


C:
Код
void memcpy128(void *destination,const void *source,int num);


А как подобным образом реализовать заливку константой (memset) блоками выше, чем 4 байта? (какими ассемблерными инструкциями?)
__inline__
Дисплей активно работает по FSMC, сбоев не замечено.

Накидал программу с 3D графикой. На разогнанном STM32F407 до 252 МГц вышло 24 FPS. Использовал софтварный текстурный мэппер, в SIMD не влазил, только VFP.

Вот что вышло: http://www.youtube.com/watch?v=mIBVAke6A80

Исходники приложил ниже:
Нажмите для просмотра прикрепленного файла

Нажмите для просмотра прикрепленного файла

В проекте применено копирование в память дисплея с помощью блоков по 128 байт (s0..s31 VFP)
__inline__
Подключил дисплей к Nucleo-144 STM32H743. Перестал показывать.
Чтением регистра возвращается правильный ID, но не инитится. Кеширование кода/данных выключено.

Вернул дисплей назад к STM32F4Discovery - всё работает. Обнаружил, что касание ножки ~CS дисплея пинцетом во время работы сносит крышу дисплею. Касание к остальным выводам не ведёт к сбоям. Если притянуть вывод ~CS к минусу через резистор 2 кОм, то касание пинцетом не влияет.

Но на STM32H743 дисплей не хочет включаться (нет развёртки, но ID читается верно). Ставил растактовки такиеже при частоте 168 МГц и потом пересчитывал для 400 МГц. Один фиг - дисплей не инитится.

Питание на дискавери 2.8V, на нуклее 3.2V.
Может из-за этого?

Куда копать?
k155la3
Поосторожнее с "касанием пинцетом". Сменили одежду или обувь - и "все пропало". sm.gif
То что при помехе на ~CS происходит "слет" - вполне естественно.
---
Из-за более высокого уровня напряжения на другой плате - вопрос. Если бы оно уменьшилось, А оно увеличено до 3.2 В.
Надо выяснить из док., какие требования у дисплея к его питанию и уровням входных линий интерфейса. (например, уровень 1 выше допустимого).
Может с этим как-то связано.



__inline__
Цитата(k155la3 @ Jul 3 2018, 15:28) *
Поосторожнее с "касанием пинцетом". Сменили одежду или обувь - и "все пропало". sm.gif
То что при помехе на ~CS происходит "слет" - вполне естественно.
---
Из-за более высокого уровня напряжения на другой плате - вопрос. Если бы оно уменьшилось, А оно увеличено до 3.2 В.
Надо выяснить из док., какие требования у дисплея к его питанию и уровням входных линий интерфейса. (например, уровень 1 выше допустимого).
Может с этим как-то связано.


Обнаружил более глобальную проблему.

FMC на отладочной плате Nucleo-H743ZI не работает как надо. Не читаются правильные значения регистров. Вместо дисплея подсоединял другую периферию - тоже не работает.

Использую Кало-КУБ + Хал для генерации инит-кода. Вижу в нём настройку GPIO, FSMC и разрешение тактирования на FMC и GPIO. Этого достаточно? Есть ли подводные камни ?

Лампочки мигают, кнопки тоже считываются, миллисекундные задержки работают. А FMC с инитом куба -не хочет.

Вызванивал все сигналы (зацикливал в программе чтение-запись по адресам, по отдельным битам данных): D0..D7, A16, WR, RD, CS - всё на месте.
k155la3
Я не полагался бы так стопроцентно на HAL куба. Скорее 50 на 50.
Если Вы исключили вопрос по уровням сигналов.
Проверьте все ли корректно по софту при миграции на H743 (файлы включения, установка типа процессора может где-то "завалялась").
Возможно где-то "недоинициализация" узла(ов) периферии или тактовой в H743 по сравнению с F407.

__inline__
Цитата(k155la3 @ Jul 5 2018, 04:05) *
Я не полагался бы так стопроцентно на HAL куба. Скорее 50 на 50.
Если Вы исключили вопрос по уровням сигналов.
Проверьте все ли корректно по софту при миграции на H743 (файлы включения, установка типа процессора может где-то "завалялась").
Возможно где-то "недоинициализация" узла(ов) периферии или тактовой в H743 по сравнению с F407.


Что удалось обнаружить. Напряжение логической "1" на линиях D[0..7] = 0.38V. Логический "0" =0V. На линиях A[0], !RD, !WR, !CS напряжения логической "1" и "0" соответственно 2.8V и 0V -что норма.

Теперь стало понятно, почему ID дисплея читался верно - потому что нулевой регистр. Был бы ненулевым, не прочлось бы.

На чтение FMC работает. Уровни на линиях D[0..7] распознаются.

Теперь осталось понять, почему же уровень напряжения логической "1" на линиях D[0..7] 0.38V, вместо 2...3.2V ...
__inline__
Обнаружил, что я не одинок, глюк присутствует ещё у одного товарища: https://community.st.com/thread/49249-stm32...spurious-writes

Цитата
A single uint16_t write under 0x68000000 address results in 4 writes to memory, out of which first write is valid data, and rest are 0, as seen on logic analyser snapshot.

Нажмите для просмотра прикрепленного файла

Вот первый блин комом как говорится. santa2.gif
jcxz
Цитата(__inline__ @ Jul 5 2018, 14:04) *
Обнаружил, что я не одинок, глюк присутствует ещё у одного товарища: https://community.st.com/thread/49249-stm32...spurious-writes

И что характерно - тот товарищ тоже поклонник калокуба. О чём-то это говорит... rolleyes.gif
__inline__
Цитата(jcxz @ Jul 5 2018, 11:18) *
И что характерно - тот товарищ тоже поклонник калокуба. О чём-то это говорит... rolleyes.gif


В данном случае калокуб тут не причем. Подосрала сама STM electronix. Ошибка кривая и аппаратная. Проблему решил, работает по крайней мере на внешней SRAM:
https://electronix.ru/forum/index.php?s=&am...t&p=1571320

Сейчас осталось вернуться LCD и раскочегарить 3D-туннель на 400 МГц при включенных кешах.

Нужно ли включать кеширование кода и данных, если программа выполняется во встроенной Flash контроллера?

Как запретить кешировать регион памяти для LCD, но оставить буферизацию? В AT91RM9200 делал это с помощью MMU, а тут как?

P.S. Я - не сторонник кало-куба, пока его использую, так как только начал знакомиться с STM32H743. И очень жаль, что SPL нет, как это было в F407 sad.gif Прийдется распиливать HAL и разбавлять с даташитами sm.gif

И почему тогда в сети куча примеров под кало-куб, а на регистрах нет нигде примеров?
jcxz
Цитата(__inline__ @ Jul 5 2018, 15:55) *
Нужно ли включать кеширование кода и данных, если программа выполняется во встроенной Flash контроллера?

Так собственно кеш в МК он для того и создаётся - чтобы кешировать FLASH. Или я не понял вопроса.... wacko.gif

Цитата(__inline__ @ Jul 5 2018, 15:55) *
Как запретить кешировать регион памяти для LCD, но оставить буферизацию? В AT91RM9200 делал это с помощью MMU, а тут как?

А зачем его запрещать?
Можно посмотреть на MPU. Возможности конечно не те что у MMU, но что-то там было.

Цитата(__inline__ @ Jul 5 2018, 15:55) *
P.S. Я - не сторонник кало-куба, пока его использую, так как только начал знакомиться с STM32H743.

Такое впечатление, что там над Вами кто-то стоит с большим дрыном и принуждает калокубить... maniac.gif
В чём проблема открыть юзер-мануал, прописать необходимый периферийный блок в виде структуры, описывающей регистры IO и писать код смотря только в мануал?

Цитата(__inline__ @ Jul 5 2018, 15:55) *
И почему тогда в сети куча примеров под кало-куб, а на регистрах нет нигде примеров?

Примеры для кого? Правильно - для чайников. И пишутся так, чтобы им понятнее было. Так 90% процентов этих читателей примеров дальше чайника и не уходят.
Да и постят эти примеры такие же чайники.
И примеры пользуются теми, кто не умеет/не хочет читать даташиты: воткнул готовый пример, заработало - ура! не заработало - идём гуглим следующий пример. В таком стиле "программирование". Вот таким хламомпримерами и наполнен инет.
__inline__
Вопрос по поводу кеша возник не случайно. Так как раньше было отображение регистров периферии в адресное пространство типа "память", то при включенном кеше данных устройство работало некорректно. Сейчас же при отображении регистров устройства в адресное пространство типа "Device" кеш данных не мешает.

Вот инфа, которая расставляет все точки над "I":
http://microsin.net/programming/arm/an4838...unit-stm32.html
http://microsin.net/programming/arm/an4839...he-stm32f7.html

И всё-же я помню, что в AT91RM9200 аттрибут в MMU "Buferable" ускорял работу с периферией. А "Cacheable" приводил к артефактам. Есть ли подобное в H743 ?

И почему ж никто не подсказал, что для внешних устройств надо было ремэпнуть банки, так как дефолтные установки ставят тип "память", а не "device"?
Про адреса явно же писал. не верю, что с FMC никто не работал.

__inline__
Всё просто замечательно! rolleyes.gif

Подключил дисплей к FMC, настроил времянки. Задействовал кеширование. Вышло 41 FPS.

Потом сделал двойную буферизацию, задействовал ДМА память-память. В итоге пока процессор рендерит один кадр, ДМА отправляет на LCD готовый кадр.
Путём таких ухищрений удалось выжать 63 FPS.

Видео (по сравнению с видео выше с STM32F407, скорость намного выше 63 vs. 24 FPS): http://www.youtube.com/watch?v=4VpX5UfkmWA

Исходники для STM32H743 Ниже. Просьба не ругаться(за кало-Куб), нужно было оценить отладочную плату и процессор STM32H743.

Нажмите для просмотра прикрепленного файла


jcxz
Цитата(__inline__ @ Jul 6 2018, 13:11) *
Видео (по сравнению с видео выше с STM32F407, скорость намного выше 63 vs. 24 FPS): http://www.youtube.com/watch?v=4VpX5UfkmWA

При FPS=24 вообще нет смысла тратить столько ног на LCD - можно по SPI подключить и получить такую же скорость.
__inline__
Цитата(jcxz @ Jul 6 2018, 13:18) *
При FPS=24 вообще нет смысла тратить столько ног на LCD - можно по SPI подключить и получить такую же скорость.

24 FPS - это общий FPS: рендеринг картинки в буфер + перекидывание буфера на дисплей, а не чисто-перекидывание на дисплей

Если перекидывание буфера на экран через SPI даст 24 FPS, то общий FPS программы упадёт до 10 и меньше.
jcxz
Цитата(__inline__ @ Jul 6 2018, 15:24) *
24 FPS - это общий FPS: рендеринг картинки в буфер + перекидывание буфера на дисплей, а не чисто-перекидывание на дисплей

Я это понял. Я и говорю, что с такой скоростью отрисовки, не нужна параллельная шина, можно использовать SPI.

Цитата(__inline__ @ Jul 6 2018, 15:24) *
Если перекидывание буфера на экран через SPI даст 24 FPS, то общий FPS программы упадёт до 10 и меньше.

"Перекидывание" даёт FPS=~36 при 45МГц SCLK и 16 бит цвета. А рисование не должно ему мешать если идёт в это время в другой буфер. Таким образом если у вас только рисование даёт 24Гц, то передача по SPI не снизит эту скорость.
__inline__
Цитата(jcxz @ Jul 6 2018, 13:29) *
Я это понял. Я и говорю, что с такой скоростью отрисовки, не нужна параллельная шина, можно использовать SPI.

"Перекидывание" даёт FPS=~36 при 45МГц SCLK и 16 бит цвета. А рисование не должно ему мешать если идёт в это время в другой буфер. Таким образом если у вас только рисование даёт 24Гц, то передача по SPI не снизит эту скорость.


Там где 24 Гц - это на STM32F407. У него 128+64 кБ памяти, хватает только на один буфер 320x240x2 и то, он реализован кусками!

Двойная буферизация в STM32H743. Но там 63 FPS.


jcxz
Цитата(__inline__ @ Jul 6 2018, 16:26) *
Там где 24 Гц - это на STM32F407. У него 128+64 кБ памяти, хватает только на один буфер 320x240x2 и то, он реализован кусками!

320*240/4=19200 - должно хватать на бОльшее.
__inline__
Цитата(jcxz @ Jul 6 2018, 17:37) *
320*240/4=19200 - должно хватать на бОльшее.


2 байта на пиксел. 16bpp.

320x240x2=150 кБ
два буфера - уже 300 кБ < 192 кБ в stm32f407 biggrin.gif
jcxz
Цитата(__inline__ @ Jul 7 2018, 07:10) *
2 байта на пиксел. 16bpp.
320x240x2=150 кБ
два буфера - уже 300 кБ < 192 кБ в stm32f407 biggrin.gif

Я понимаю, что можно и 4 байта на пиксел положить, но зачем если памяти мало??
У меня 320x240x4 (4bpp конечно-же) в STM32F429 во внутренней памяти и буфер прекрасно влазит в CCM.
__inline__
Цитата(jcxz @ Jul 7 2018, 07:35) *
Я понимаю, что можно и 4 байта на пиксел положить, но зачем если памяти мало??
У меня 320x240x4 (4bpp конечно-же) в STM32F429 во внутренней памяти и буфер прекрасно влазит в CCM.

Видите ли, в чём дело... Вы со своей колокольни смотрите на проблему. Я же со своей. Тот туннель, что я выкладывал - ну никак не смотрится в 16 цветах - слишком убого. И в 256 цветах тоже будет плохо смотреться. Поэтому было принято решение использовать 65536 цветов.

Цель была - перенести алгоритм построения трёхмерного туннеля из этой программы: http://www.sulaco.co.za/opengl_project_racing_tunnel.htm , не угробив при этом цветопередачу текстуры.
jcxz
Цитата(__inline__ @ Jul 7 2018, 09:47) *
Тот туннель, что я выкладывал - ну никак не смотрится в 16 цветах - слишком убого. И в 256 цветах тоже будет плохо смотреться. Поэтому было принято решение использовать 65536 цветов.

Туннель - это конечно хорошо. Но зачем он в плане embedded? Какой практический прок? Для всяких смартфонных девайсов - спору нет, но там вроде как и процы немного другие....
А вот для GUI какого-нить девайса 16 цветов - обычно вполне достаточно.
__inline__
Цитата(jcxz @ Jul 7 2018, 07:56) *
Туннель - это конечно хорошо. Но зачем он в плане embedded? Какой практический прок? Для всяких смартфонных девайсов - спору нет, но там вроде как и процы немного другие....
А вот для GUI какого-нить девайса 16 цветов - обычно вполне достаточно.

Готовлю плацдарм для прыжка в будущее rolleyes.gif
Если быть точным, то у меня чисто академический интерес - пощупать Cortex-M7, посмотреть его достоинства и недостатки.
__inline__
Собственно, что мы затеваем: http://vrtp.ru/index.php?showtopic=30174&st=0&

Но хочется большего sm.gif
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.