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

Запуск LCD в 4-bit mode на AT91SAM7S

Запускаю на своем модуле ARM7MODA LCD индикатор из серии KS0066. Режим этот нужен, так что вопрос принципиальный.

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

Жутко принципиальный момент, по этому хочется его запустить.

 

Итак, 8bit mode - запустился на раз плюнуть, код я подставил свой старый, уже рабочий. Но был затык, и как оказалось, выяснил опытным путем, что индикатор мне попался жуткий тормозяра... каких я не встречал до этого.

Индикатор NEWTEC NC08082A. Ну то ладно, главное что нашел виновника, это - его медлительность.

 

Потом залез в его даташит, там приведены намного меньшие таймауты необходимые для работы... А по моему коду получается что нужно намного большие временные периоды между RS -> E -> Data.

 

А вот 4bit mode - напрочь не хочет заводиться. И вот тут у меня какой то шоковый ступор. Так как 4 бит я уже запускал несколько штук ранее. А на этом индикаторе - не получается.

 

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

На не оптимизированный код в 4bit mode не обращайте внимания, это я уже ради удобства выснения проблемы все перенес в один фрагмент

 

#define	_RS	_B8
#define	_E	_B9

#define LCD_TIME_FAST  (10)
#define LCD_TIME_SLOW  (50)
#define LCD_TIME  LCD_TIME_SLOW
...
...
//-----------------------------------------------------------
void LCD_Config(void)
{

#ifdef LCD_4_BITS
 AT91PS_SYS  regs = AT91C_BASE_SYS;

tick(600*LCD_TIME); regs->PIOA_ODSR &=~_RS;	//   RS=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
delay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;

delay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x20);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x80);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
delay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x00);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x80);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
delay();	
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x00);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x10);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
delay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x00);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		  regs->PIOA_ODSR |= (0x30);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
delay();
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_RS;	//   RS=0;
#endif /*LCD_4_BITS*/


#ifdef LCD_8_BITS
unsigned char i=0, init_value[] = { 0x01, 0x02, 0x06, 0x0c, 0x14, 0x38 }; /* 16x2 */ 

for (i=0; i<sizeof(init_value); i++) { 
  lcd_cmd ( init_value[i] );
}
#endif /*LCD_8_BITS*/

} /* LCD_Config() */

//-----------------------------------------------------------
void lcd_cmd (unsigned char ch)
{
 AT91PS_SYS  regs = AT91C_BASE_SYS;

#ifdef LCD_4_BITS
udelay();
tick(600*LCD_TIME); regs->PIOA_ODSR &=~_RS;//   RS=0;
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		   regs->PIOA_ODSR |= (ch&0xf0);
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
udelay();
tick(60*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(60*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
tick(1);		   regs->PIOA_ODSR |= (ch&0x0f)<<4;
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
tick(60*LCD_TIME); regs->PIOA_ODSR &=~_RS;	//   RS=0;
#endif /*LCD_4_BITS*/

#ifdef LCD_8_BITS
tick(600*LCD_TIME); regs->PIOA_ODSR &=~_RS;//   RS=0;
tick(6*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(6*LCD_TIME); regs->PIOA_ODSR &= 0xffffff00;
tick(6*LCD_TIME); regs->PIOA_ODSR |= ch;
tick(6*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
tick(6*LCD_TIME); regs->PIOA_ODSR &=~_RS;	//   RS=0;
#endif /*LCD_8_BITS*/
} /* lcd_cmd() */

//-----------------------------------------------------------
// Set address of first byte on desired row
void lcd_xy( unsigned char y, unsigned char x )
{	
 unsigned char  LCD_ROW_ADDRESS[4] = { 0x00, 0x40, 0x14, 0x54 };
 unsigned char  AddrXYData;
 AT91PS_SYS	 regs = AT91C_BASE_SYS;

AddrXYData = LCD_ROW_ADDRESS[y]+x;

#ifdef LCD_4_BITS
tick(60*LCD_TIME); regs->PIOA_ODSR   &=~_RS; //   RS=0;
 tick(40*LCD_TIME); regs->PIOA_ODSR  |=_E;	//   E=1;
 tick(40*LCD_TIME); regs->PIOA_ODSR  &= 0xffffff0f;
 tick(1);		  regs->PIOA_ODSR  |=0x80|(AddrXYData&0xF0);
 tick(40*LCD_TIME); regs->PIOA_ODSR  &=~_E;	//   E=0;
  tick(40*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
  tick(40*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
  tick(1);		  regs->PIOA_ODSR |=(AddrXYData&0x0F)<<4;
  tick(40*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
#endif /*LCD_4_BITS*/

#ifdef LCD_8_BITS
tick(6*LCD_TIME); regs->PIOA_ODSR &=~_RS;//   RS=0;
tick(4*LCD_TIME); regs->PIOA_ODSR |=_E;	//   E=1;
tick(4*LCD_TIME); regs->PIOA_ODSR &= 0xffffff00;
tick(1);		  regs->PIOA_ODSR |=(0x80|AddrXYData);
tick(4*LCD_TIME); regs->PIOA_ODSR &=~_E;	//   E=0;
#endif /*LCD_8_BITS*/
} /* lcd_xy() */

//-----------------------------------------------------------
/* Show message on LCD*/
void lcd_char( unsigned char value )
{ 
 AT91PS_SYS	 regs = AT91C_BASE_SYS;
 unsigned char  kod;

kod = value;
kod = lcd_recode( value );

#ifdef LCD_4_BITS
tick(30*LCD_TIME); regs->PIOA_ODSR   |=_RS; //   RS=1;
 tick(30*LCD_TIME); regs->PIOA_ODSR  |=_E;  //   E=1;
 tick(20*LCD_TIME); regs->PIOA_ODSR  &= 0xffffff0f;
 tick(1);		  regs->PIOA_ODSR  |=((kod &0xF0));
 tick(20*LCD_TIME); regs->PIOA_ODSR  &=~_E; //   E=0;
  tick(30*LCD_TIME); regs->PIOA_ODSR |=_E;  //   E=1;
  tick(20*LCD_TIME); regs->PIOA_ODSR &= 0xffffff0f;
  tick(1);		  regs->PIOA_ODSR |=((kod &0x0F)<<4);
  tick(20*LCD_TIME); regs->PIOA_ODSR &=~_E; //   E=0;
#endif /*LCD_4_BITS*/

#ifdef LCD_8_BITS
tick(3*LCD_TIME); regs->PIOA_ODSR |=_RS;	 //   RS=1;
tick(3*LCD_TIME); regs->PIOA_ODSR |=_E;	 //   E=1;
tick(2*LCD_TIME); regs->PIOA_ODSR &= 0xffffff00;
tick(1);		  regs->PIOA_ODSR |= kod;
tick(2*LCD_TIME); regs->PIOA_ODSR &= ~_E; //   E=0;
#endif /*LCD_8_BITS*/
} /* lcd_char() */

...
...

 

...тормознутость можете сами заметить по 60*LCD_TIME

 

Вопрос - Где же что не правильно?

Или есть такое что индикатор не поддерживает этот режим?

Так должен - даташит обещает...

Изменено пользователем IgorKossak
Пользуйтесь тэгами [codebox]

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


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

Боже ж мой! Да подключите вы PCF8575 к аппаратному I2C МК, а к ней в свою очередь этот ваш символьный LCD и используйте на здоровье любимый вами 8-ми битный режим вместо этого "ногодрыжества". Ногодрыжество на ARM это совершенно специальный вид секса с элементами грубого мазохизма ;)

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


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

Код, уж простите, просто чудовищный. И это еще самый мягкий эпитет, который к нему можно применить.

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


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

Rezident, а чем ногодрыжество через PCF8575 в программе будет принципиально отличатся от простого ногодрыжества?

Да еще и в используемой плате, где стоит AT91SAM7S с его "фирменным" i2c.

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


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

Тем более, что программа пишется один раз, ногами дрыгает не юзер, а контроллер (ему не надоест), а вот тратиться на PCF8575 абсолютно в каждый экземпляр устройства таки придётся.

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


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

Да, читать такой код сложновато. Если правильно понял, то в первых трех обращениях надо не regs->PIOA_ODSR |= (0); (что само по себе бессмысленно), а regs->PIOA_ODSR |= (0x30);

И вообще, если уж идти таким путем:

uint32_t Temp = regs->PIOA_OWSR;
regs->PIOA_OWER = 0xF0;
regs->PIOA_OWDR = ~0xF0;

regs->PIOA_SODR = _E;   // E = 1
regs->PIOA_ODSR = 0x30;
regs->PIOA_CODR = _E;   // E = 0
....
....
regs->PIOA_OWDR = 0xF0;
regs->PIOA_OWER = Temp;

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


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

Rezident, а чем ногодрыжество через PCF8575 в программе будет принципиально отличатся от простого ногодрыжества?
Принципиально? - ничем. И там и там ногодрыжество. Однако ТС по какой-то причине экономит выводы МК, выделенные для подключения LCD-модуля. Вот я и предлагаю ему расширить их количество. Тем более, что с 8-ми битным подключением у него LCD работает (по его словам).

Да еще и в используемой плате, где стоит AT91SAM7S с его "фирменным" i2c.
А что, там багов немеряно? У LPC17хх и LPC11xx подключение I2C никаких проблем не вызывало. :cranky: Хотя оно и понятно - все же родное Филипсовское. :rolleyes:

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


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

А что, там багов немеряно?

Почему немеряно, очень даже меряно:

Раз. Два

Причем LPC17хх и LPC11xx?

Зачем человеку по лишним граблям ходить?

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


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

Код, уж простите, просто чудовищный. И это еще самый мягкий эпитет, который к нему можно применить.

да я знаю, вы меня не задели ))

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

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


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

Вот что у меня работает на SAM7S32 в четырёхбитной позе. Задержки для MCK=55МГц

;
; lcd HD44780 support routines
;

 INCLUDE common.inc


LCD_RS_LINE EQU				0x00000004
LCD_E_LINE EQU				0x00000008


AREA	TEXT, CODE, READONLY
ARM


; задержка примерно на 350 нс
lcdDelayE
ldr		r10, =4
lcdDelayE_loop
subs	r10, r10, #1
bne		lcdDelayE_loop
bx		LR


; задержка примерно на 40 мкс
lcdDelay50us
ldr   	r10, =280
b		lcdDelayE_loop


; задержка примерно на 250 мкс
lcdDelay250us
ldr   	r10, =1750
b		lcdDelayE_loop


EXPORT	lcdDelay2500us
; задержка примерно на 2500 мкс
lcdDelay2500us
ldr   	r10, =17000
b		lcdDelayE_loop


EXPORT  delay2500us
delay2500us
stmfd	SP!, {r10, LR}
bl		lcdDelay2500us
ldmfd	SP!, {r10, PC}


; отправить команду в LCD
; IN
;    r9 - байт команды
lcdSendCommand
stmfd	SP!, {r9,r10,LR}
; ставим признак команды
str		r5, [r7, #PIO_CODR]
; задержка
bl		lcdDelayE
; дёргаем линией Е
str		r6, [r7, #PIO_SODR]
;bl		lcdDelayE
; выставляем старшую половину байта
str		r9, [r7, #PIO_ODSR]
bl		lcdDelayE
;
str		r6, [r7, #PIO_CODR]
;bl		lcdDelayE
bl		lcdDelayE
lcdSend4BitsBackdoor
; дёргаем линией Е
str		r6, [r7, #PIO_SODR]
;bl		lcdDelayE
; выставляем вторую половину байта
mov		r10, r9, lsl #4
str		r10, [r7, #PIO_ODSR]
bl		lcdDelayE
;
str		r6, [r7, #PIO_CODR]
bl		lcdDelay50us
; на выход
ldmfd	SP!, {r9,r10,PC}


; отправить 4 бита команды в LCD
; IN
;    r9 - 4 бита команды
lcdSendCommandHalf
stmfd	SP!, {r9,r10,LR}
; ставим признак команды
str		r5, [r7, #PIO_CODR]
b		lcdSend4BitsBackdoor


; отправить байт данных в LCD
; IN
;    r9 - байт данных
lcdSendData
str		LR, [sP, #-4]!
; ставим признак данных
str		r5, [r7, #PIO_SODR]
; задержка
bl		lcdDelayE
; дёргаем линией Е
str		r6, [r7, #PIO_SODR]
;bl		lcdDelayE
; выставляем старшую половину байта
str		r9, [r7, #PIO_ODSR]
bl		lcdDelayE
;
str		r6, [r7, #PIO_CODR]
;bl		lcdDelayE
bl		lcdDelayE
; дёргаем линией Е
str		r6, [r7, #PIO_SODR]
;bl		lcdDelayE
; выставляем вторую половину байта
mov		r10, r9, lsl #4
str		r10, [r7, #PIO_ODSR]
bl		lcdDelayE
;
str		r6, [r7, #PIO_CODR]
bl		lcdDelay50us
; на выход
ldr		PC, [sP], #4


; инициализация LCD
lcdFirstInit
stmfd	SP!, {r0,r5-r7,r9,r10,LR}
ldr		r7, =PIO_BASE
; set lines PA4-PA7 for parallel output
ldr		r5, =0x000000F0
str		r5, [r7, #PIO_OWER]
add		r5, #0x0C
str		r5, [r7, #PIO_CODR]
str		r5, [r7, #PIO_OER]
ldr		r5, =LCD_RS_LINE
ldr		r6, =LCD_E_LINE
; delay
ldr		r0, =12
lcdFirstInit_delay
bl		lcdDelay2500us
subs	r0, #1
bne		lcdFirstInit_delay
; 3 команды инициализации
ldr		r9, =0x03
bl		lcdSendCommandHalf
bl		lcdDelay2500us
bl		lcdSendCommandHalf
bl		lcdDelay250us
bl		lcdSendCommandHalf
bl		lcdDelay250us
ldr		r9, =0x02
bl		lcdSendCommandHalf
bl		lcdDelay250us
ldr		r9, =0x28
bl		lcdSendCommand
ldr		r9, =0x08
bl		lcdSendCommand
ldr		r9, =0x01
bl		lcdSendCommand
bl		lcdDelay2500us
ldr		r9, =0x06
bl		lcdSendCommand
ldr		r9, =0x0C
bl		lcdSendCommand
ldmfd	SP!, {r0,r5-r7,r9,r10,PC}

EXPORT lcdFirstInit

; вывод строчки на экран, первый байт - адрес ОЗУ LCD, признак конца строки - 0
; IN
;  r0 - адрес строчки
lcdPrintString
stmfd	SP!, {r0,r5-r7,r9,r10,LR}
ldr		r5, =LCD_RS_LINE
ldr		r6, =LCD_E_LINE
ldr		r7, =PIO_BASE
; команда установки адреса
ldrb	r9, [r0], #1
orr		r9, r9, #0x80
bl		lcdSendCommand
; теперь выводим символы
lcdPrintString_loop
ldrb	r9, [r0], #1
tst		r9, r9
beq		lcdPrintString_exit
bl		lcdSendData
b		lcdPrintString_loop
lcdPrintString_exit
ldmfd	SP!, {r0,r5-r7,r9,r10,PC}

EXPORT lcdPrintString


; установка курсора
; IN
;	 в r0 - новый адрес курсора
lcdSetCursor
stmfd	SP!, {r0,r5-r7,r9,r10,LR}
ldr		r5, =LCD_RS_LINE
ldr		r6, =LCD_E_LINE
ldr		r7, =PIO_BASE
mov		r9, r0
orr		r9, r9, #0x80
bl		lcdSendCommand
ldmfd	SP!, {r0,r5-r7,r9,r10,PC}

EXPORT	lcdSetCursor


; вывод строчки на экран, признак конца строки - 0
; IN
;  r0 - адрес строчки
lcdPrint
stmfd	SP!, {r0,r5-r7,r9,r10,LR}
ldr		r5, =LCD_RS_LINE
ldr		r6, =LCD_E_LINE
ldr		r7, =PIO_BASE
; выводим символы
lcdPrint_loop
ldrb	r9, [r0], #1
tst		r9, r9
beq		lcdPrint_exit
bl		lcdSendData
b		lcdPrint_loop
lcdPrint_exit
ldmfd	SP!, {r0,r5-r7,r9,r10,PC}

EXPORT lcdPrint


END

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


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

да я знаю, вы меня не задели ))

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

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


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

Бросается в глаза, что в оригинальном проекте ничего в OWER не пишется, для "ногодрыгательства" продолжают читаиться и писаться биты ODSR, которые read-only.

Приаттачен работающий кусок для 4-х битного режима. На полный проект (лежащий в сети в открытом виде) ссылочку приведу, если надо.

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

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


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

Бросается в глаза, что в оригинальном проекте ничего в OWER не пишется, для "ногодрыгательства" продолжают читаиться и писаться биты ODSR, которые read-only.

Приаттачен работающий кусок для 4-х битного режима. На полный проект (лежащий в сети в открытом виде) ссылочку приведу, если надо.

 

В ODSR можно писать при соответствующих настройках PIO. Таким образом достигается одновременность выставления, например, шины адреса или данных.

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


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

В ODSR можно писать при соответствующих настройках PIO. Таким образом достигается одновременность выставления, например, шины адреса или данных.

Знаю и использую. У автора в приведённом им фрагменте кода настроек не видно.

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


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

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

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

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

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

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

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

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

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

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