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

Использую отладочную плату STM32F4Discovery (контроллер STM32F407) и LCD, подключенный по FSMC (дисплей от телефона Sony Ericsson K800i).

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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);
}

Изменено пользователем IgorKossak
[codebox] для длинного кода, [code] - для короткого!

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


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

Глючит от отражений в линии. Спасают резисторы последовательно с выходами МК, пара десятков омов. А конденсаторы выкинуть, это ненаучно.

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


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

Надо посмотреть по док. на дисплей, выдерживаются ли таймауты от ~CS до-после RD WR.

Для скоростных интерфейсов сигнальные линии в кабеле должны чередоваться с "обратным" GND (как данные так и управление).

И линии передачи должны быть согласованы (выше, ViKo). Кабель может обернут фольгой-экраном.

(длина кабеля на Вашем девайсе уже "ощутимая"). Со стороны процессора должы работать push-pull выходы.

В телефоне стоят конденсаторы, тк (возможно) скорость интерфейса меньше, а есть сильный уровнеь помех от радиоизлучения евойного.

 

 

 

 

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


Ссылка на сообщение
Поделиться на другие сайты
Глючит от отражений в линии. Спасают резисторы последовательно с выходами МК, пара десятков омов. А конденсаторы выкинуть, это ненаучно.

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

 

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

2) 47 Ом - Не работает

3) 300 Ом - Не работает

 

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

 

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

 

Надо посмотреть по док. на дисплей, выдерживаются ли таймауты от ~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 ? Это синхронный такт для пина или фильтр подавления глитчей?

 

Для скоростных интерфейсов сигнальные линии в кабеле должны чередоваться с "обратным" GND (как данные так и управление).

В этой модели дисплея не чередуются с GND.

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

 

Кабель может обернут фольгой-экраном.

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

 

Со стороны процессора должы работать push-pull выходы.

 

Так и есть, подтяжки и open drain не включены. Код инита GPIO, FSMC привел в первом сообщении.

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

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


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

Тогда нужно нарисовать на бумаге временную диаграмму обмена по шине и задать правильно Address_setup, Address_hold, Data_duration.

Заменил резистор на 22 Ом, припаял близко к ноге Discovery, насколько возможно. Не работает.

О-ля-ля... так от ноги МК до ноги Дискавери уже несколько сантиметров.

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

Задает ток в момент переключения выхода, а потом возвращается к стандартному. Чтобы перезарядить емкость подключенной к порту цепи. Малая скорость задает малый ток, заваленный фронт, отражения не проявляются так заметно.

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


Ссылка на сообщение
Поделиться на другие сайты
Тогда нужно нарисовать на бумаге временную диаграмму обмена по шине и задать правильно 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-битной шины выигрыша не даст?

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

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


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

По моему, шину нужно 8-битовой определить. А посылать можно 16-битовые слова, и контроллер их в 2 этапа передаст. Во всяком случае 16/32 так делается. Дожно быть описано в документации.

 

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


Ссылка на сообщение
Поделиться на другие сайты
По моему, шину нужно 8-битовой определить. А посылать можно 16-битовые слова, и контроллер их в 2 этапа передаст. Во всяком случае 16/32 так делается. Дожно быть описано в документации.

Я так и сделал. Всё работает!

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

 

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

 

И как дергается строб !CS - каждый байт или 1 раз за всю 16/32-битную пересылку?

 

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


Ссылка на сообщение
Поделиться на другие сайты
И как дергается строб !CS - каждый байт или 1 раз за всю 16/32-битную пересылку?
А вот неизвестно. Может один раз, а может и прервать, если что-то более приоритетное вклинится.

 

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


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

Дергается на каждый байт. Как для обычных 8 битовых пересылок.

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


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

Ещё проделал эксперимент.

 

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

 

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

 

Хотел на STM32F407 повешать 2 устройства на FSMC, а тут видать облом - только NE1 есть и всё. Остальные NE2-4 только в BGA :(

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


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

Адресом разделяйте.

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


Ссылка на сообщение
Поделиться на другие сайты
Дергается на каждый байт. Как для обычных 8 битовых пересылок.
Если данные успевают поступать, то всё что в пределах одного #CS объединяется под ним. Вот недавно делал. Тут, правда, 16-битные пересылки, но это не меняет сути. Все 10 записей под одним #CS происходят.

__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
}

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


Ссылка на сообщение
Поделиться на другие сайты
Если данные успевают поступать, то всё что в пределах одного #CS объединяется под ним. Вот недавно делал. Тут, правда, 16-битные пересылки, но это не меняет сути. Все 10 записей под одним #CS происходят.

__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, интересно глянуть его на предмет бурстов.

 

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


Ссылка на сообщение
Поделиться на другие сайты
Скиньте плиз свой инит FSMC, интересно глянуть его на предмет бурстов.

Прошу прощения за магические числа, надо будет переписать... :(

  //Инициализация FMC для доступа к регистрам CPLD
  FMC_Bank1->BCR1 = 0x1091;
  FMC_Bank1->BTR1 = 0x0FFF01F2;

 

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 нс (плюс/минус точно не помню).

        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]

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


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

Для публикации сообщений создайте учётную запись или авторизуйтесь

Вы должны быть пользователем, чтобы оставить комментарий

Создать учетную запись

Зарегистрируйте новую учётную запись в нашем сообществе. Это очень просто!

Регистрация нового пользователя

Войти

Уже есть аккаунт? Войти в систему.

Войти
Авторизация