Управление дисплеем с помощью SPI.
- Войдите на сайт для отправки комментариев
Пт, 01/11/2013 - 11:51
Добрый день! Есть дисплей LPH8731-3C, для него был написан вот такой код, в котором было использованы куски из других работ, в том числе с этого форума.
//Определяем пины для подключения дисплея #define LCD_CS 10 #define LCD_RESET 3 #define LCD_RS 4 #define LCD_CLK 13 #define LCD_DATA 11 #define CMD 0 #define DAT 1 byte color; //Определяем значения вкл/выкл пинов #define LCD_CLK_ON digitalWrite(LCD_CLK,HIGH); #define LCD_CLK_OFF digitalWrite(LCD_CLK,LOW); #define LCD_RS_ON digitalWrite(LCD_RS,HIGH); #define LCD_RS_OFF digitalWrite(LCD_RS,LOW); #define LCD_CS_OFF digitalWrite(LCD_CS,LOW); #define LCD_CS_ON digitalWrite(LCD_CS,HIGH); #define LCD_RESET_ON digitalWrite(LCD_RESET,HIGH); #define LCD_RESET_OFF digitalWrite(LCD_RESET,LOW); void setup() { pinMode (LCD_CS, OUTPUT); pinMode (LCD_RESET, OUTPUT); pinMode (LCD_RS, OUTPUT); pinMode (LCD_CLK, OUTPUT); pinMode (LCD_DATA, OUTPUT); LCD_init (); } void loop() { for (int i = 0; i < 101; i++) { for (int j = 0; j < 80; j++) { Send_to_lcd(CMD,0x2a); Send_to_lcd(DAT, i); Send_to_lcd(DAT, 100); Send_to_lcd(CMD, 0x2b); Send_to_lcd(DAT, j+1); Send_to_lcd(DAT, 80); Send_to_lcd(CMD,0x2c); Send_to_lcd(DAT, 0x00); } } for (int i = 0; i < 101; i++) { for (int j = 0; j < 80; j++) { //command Send_to_lcd(CMD, 0x2a); //data Send_to_lcd(DAT, i); Send_to_lcd(DAT, 10); Send_to_lcd(CMD, 0x2b); //data Send_to_lcd(DAT,j+1); Send_to_lcd(DAT, 50); Send_to_lcd(CMD, 0x2c); //data Send_to_lcd(DAT, 0x16); }} } void reset () //Функция сброса дисплея, ПОРТИРОВАНА { LCD_CS_OFF; digitalWrite(LCD_DATA,LOW); LCD_RESET_OFF; delay(100); LCD_RESET_ON; delay(500); LCD_CS_ON; delay(5); LCD_CS_OFF; } void Send_to_lcd (unsigned char RS, unsigned char data)//портирована { if (RS==HIGH){ LCD_RS_ON; LCD_CS_OFF; shiftOut(LCD_DATA, LCD_CLK, MSBFIRST, data); LCD_CS_ON; } else { LCD_RS_OFF; LCD_CS_OFF; shiftOut(LCD_DATA, LCD_CLK, MSBFIRST, data); LCD_CS_ON; } } void LCD_init ()//портирована { reset (); Send_to_lcd(CMD,0x01); //reset sw delay(50); Send_to_lcd(CMD,0xc6); //initial escape delay(50); Send_to_lcd(CMD,0xb9); //Refresh set Send_to_lcd(DAT,0x00); Send_to_lcd(CMD,0xb6); //Display control Send_to_lcd(DAT,0x80); // Send_to_lcd(DAT,0x04); // Send_to_lcd(DAT,0x8a); // Send_to_lcd(DAT,0x54); // Send_to_lcd(DAT,0x45); // Send_to_lcd(DAT,0x52); // Send_to_lcd(DAT,0x43); // Send_to_lcd(CMD,0xb3); //Gray scale position set 0 Send_to_lcd(DAT,0x02); // Send_to_lcd(DAT,0x0a); // Send_to_lcd(DAT,0x15); // Send_to_lcd(DAT,0x1f); // Send_to_lcd(DAT,0x28); // Send_to_lcd(DAT,0x30); // Send_to_lcd(DAT,0x37); // Send_to_lcd(DAT,0x3f); // Send_to_lcd(DAT,0x47); // Send_to_lcd(DAT,0x4c); // Send_to_lcd(DAT,0x54); // Send_to_lcd(DAT,0x65); // Send_to_lcd(DAT,0x75); // Send_to_lcd(DAT,0x80); // Send_to_lcd(DAT,0x85); // Send_to_lcd(CMD,0xb5); //Gamma curve Send_to_lcd(DAT,0x01); // Send_to_lcd(CMD,0xb7); //Temperature gradient Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x00); // Send_to_lcd(CMD,0xbd); //Common driver output select Send_to_lcd(DAT,0x00); // /* Send_to_lcd(CMD,0x33); //Vertical scrolling definition - Границы вертикальной прокрутки Send_to_lcd(DAT,0x00); //Число линий, используемых в качестве верхней фиксированной области дисплея (max - 0x53) Send_to_lcd(DAT,0x53); //Определяем область прокрутки Send_to_lcd(DAT,0x00); //Число линий, используемых в качестве нижней фиксированной области дисплея Send_to_lcd(CMD,0x37); //Vertical scrolling start adress Send_to_lcd(DAT,0x00); */ Send_to_lcd(CMD,0x36); //Memory access control - Метод доступа к дисплейной памяти (установка нулевого адреса страницы и столбца, направление записи в память дисплея) Send_to_lcd(DAT,0x48); //6-й бит, установленный в "1" делает адресацию столбца - слева-направо, а 3-й бит в "1" - порядок RGB (а в даташите - ошибка!!!) Send_to_lcd(CMD,0x2d); //Colour set Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x03); // Send_to_lcd(DAT,0x05); // Send_to_lcd(DAT,0x07); // Send_to_lcd(DAT,0x09); // Send_to_lcd(DAT,0x0b); // Send_to_lcd(DAT,0x0d); // Send_to_lcd(DAT,0x0f); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x03); // Send_to_lcd(DAT,0x05); // Send_to_lcd(DAT,0x07); // Send_to_lcd(DAT,0x09); // Send_to_lcd(DAT,0x0b); // Send_to_lcd(DAT,0x0d); // Send_to_lcd(DAT,0x0f); // Send_to_lcd(DAT,0x00); // Send_to_lcd(DAT,0x05); // Send_to_lcd(DAT,0x0b); // Send_to_lcd(DAT,0x0f); // Send_to_lcd(CMD,0xba); //Voltage control //Send_to_lcd(DAT,0x2f); // Send_to_lcd(DAT,0x6d);//из сектча Send_to_lcd(DAT,0x03);//из скетча Send_to_lcd(CMD,0x25); //Установка контраста Send_to_lcd(DAT,0x29); //от этого значения зависит контрастность изображения. Send_to_lcd(CMD,0xbe); //Power control Send_to_lcd(DAT,0x58); // Send_to_lcd(CMD,0x3a); //Информация о выводе пикселя //#ifdef _8_BIT_COLOR Send_to_lcd(DAT,0x02); //8-ми битный цвет //#else // Send_to_lcd(DAT,0x03); //12-ти битный цвет // #endif Send_to_lcd(CMD,0x03); //Booster voltage ON delay(40); Send_to_lcd(CMD,0x11); //Выход из спящего режима delay(20); //Перед включением ждем 20 миллисекунд Send_to_lcd(CMD,0x29); //Включение дисплея }
Беда в том, что все это работает безумно медленно, обновление экрана за 9 секунд это не айс. Хотелось бы для этих целей использовать SPI, на сколько я понимаю дисплей именно по такому протоколу и работает, но как использовать библиотеку я пока не пойму. Пробовал, но не получилось. Может кто то поможет написать пример, на основе даннного скетча?
Прежде всего мне не понятно как работать с CS, обязательно ли называть пин как в примерах? И какой режим работы интерфеса мне нужен?
А разве shiftout это не из библиотеки SPI?
В вашем коде место вызова этой функции это самое важное место для производительности
Нет, SPI аппаратный интерфейс. И скорость там должна быть на порядок выше.
Нет, SPI аппаратный интерфейс. И скорость там должна быть на порядок выше.
в терминах стоит быть аккуратным. SPI это стандарт синхронного последовательного обмена данными. Реализация может быть хоть железной хоть програмной. И та и другая будет называться SPI. Нужно очень постараться в кривонаписании программной реализации, чтобы разница была на порядок. По крайней мере на avr эта разница не такая драматичная. Я не использую ардуиновских библиотек для SPI, поэтому и спрашиваю откуда в скетче функция shiftout? В начале скетча нет ни одной директивы #include, чтобы это понять. Может быть скетч не полный
Хотя не важно, вместо shiftout надо поставить методы из стандартно для ардуино SPI библиотеки, не забыв прочитать к ней описание. Настройки Spi следуют из скетча - младший бит вперед. Со скоростью можно поиграть. Начать с предлелителя на 4 и довести до 1. Минимальный делитель при котором булет работать дисплей и обеспечит наибольшую скорость
Ошибся, MSB это старшим битом вперед, вам нужны буду эти методы для настройки:
Вроде shiftOut(LCD_DATA, LCD_CLK, MSBFIRST, data); надо заменить на SPI.transfer( data);
Не забыть перед этим проиницилизировать: SPI.begin();
Выводы LCD_DATA и LCD_CLK заменяются на аппаратные выводы SPI..
Взял кусочек кода, который отправляли тут на форуме, и чуть переписал с ипользованием SPI как тут писали товарищи, не работает именно кусок с SPI, что бы небыло вопросов о работе вообще.
В моем примере мне надо CS дергать вниз, на сколько я понимаю CS и SS из описния библиотеки SPI это одно и то же. В какое он состояние переходит при инициализации интерфеса?
Вот реализация begin
Тут видно, что ss переводится в high.
Получается что по этому ничего не работает?
Вот реализация transfer
У меня Duemilanova, если что вдруг. Есть какие то мысли?
вы вопросы здесь для чего задаете? вам MaksMS совершенно конкретный совет дал. Вы его проигнорировали, начитались разрозненной ерунды. Пользуетесь ардуино - читайте первоисточники http://arduino.cc/en/Reference/SPI
Я конечно понимаю, что код длинный, вы бы хоть в конец посмтрели. Я же написал свои конкретные вопросы и именно первоисточник я и цитирую. И все равно меня не покидает мысли что вы мой пости ли не прочитали ил не поняли. Еще раз повторяю - я сделал именно как советовали - не заработало, именно та часть, которая должна испльзовать SPI. То, что код, который я привел последним отличается от того что я приводил в первом посте - всего лишь значит, что я использую этот кусок как более удобный в отладке. И он так же хорошо работает, но не через SPI.
Я конечно понимаю, что код длинный, вы бы хоть в конец посмтрели. Я же написал свои конкретные вопросы и именно первоисточник я и цытирую. И все равно меня не покидает мысли что вы мой пости ли не прочитали ил не поняли.
я прочитал ваши посты, но извините, не вижу в них ни одного осознанного вопроса, идет повествование
вы привели пример реализации SPI transfer прямым обращением к регистрам МК. Зачем? Вы попробовали просто взять и использовать стандартную библиотеку SPI? Этот совет в этой ветке звучит уже 4-й раз. Я не знаю в каких форумах вы нахватали слухов и кусков кода, поэтому что-то на ваше повествование ответить сложно. Про пин SS написано по моей ссылке выше. обычно его не используют, оставляют не подключенным, потому что его подключение не позволяет подключать к шине SPI больше одного устройства. С одним устройством можно использовать именно его
Вы бы в эту библиотеку заглянули, и унали бы что там написано...эх зажили бы...Я ведь вам и привел реализацию из библотеки то...для наглядности.
А спрашиваю я уже третий раз, при вызове последовательнсоти begin transfer end как меняется cs? он же ss.
Ничто не мешает после begin установить нужный уровень CS по умолчанию,а потом его уже дергать в нужную сторону..
Вы бы в эту библиотеку заглянули, и унали бы что там написано...эх зажили бы...Я ведь вам и привел реализацию из библотеки то...для наглядности.
А спрашиваю я уже третий раз, при вызове последовательнсоти begin transfer end как меняется cs? он же ss.
зачем мне заглядывать в библиотеку которой я не пользуюсь? Но вы могли бы ее взять и просто использовать вместо того, чтобы разбираться с чужими кусками кода. Если же хотите разобраться с сутью происходящего, то читайте раздел SPI (19-й параграф), если у вас МК мега 328p то тут http://www.atmel.com/Images/Atmel-8271-8-bit-AVR-Microcontroller-ATmega48A-48PA-88A-88PA-168A-168PA-328-328P_datasheet.pdf
Там все подробно расписано и про то что происходит и про SS в частности.
В частности. CS - chip select или что в данном контексте тоже самое SS - slave select используется для активации того устройства на шине SPI с которым в данный момент МК производит сессию связи. Обычно для активации используется логический ноль (надо смотреть что написано в документе на конкретное устройство/чип). Логика простая - в начале любого обмена с устройством выставляем на CS ноль, по завершении обмена ставим там единицу.
посмотрите в свой код - у вас перед каждым shiftOut стоит
LCD_CS_OFF - перевод CS в ноль
все что вам нужно - в setup() сделать инициализацию библиотеки SPI, настроить на нужный режим и это нужно сделать до первого вызова shifyOut(). Сами shiftOut() заменить на transfer()
Почему собственно так было сделано, как у меня сейчас - что бы небыло проблем с инициализацие дисплея. То есть на момент инициализации SPI дисплей готов принимать команды. В чем осбственно проблема инициализировать SPI в теле?
Нашел я реализацию вот такую. http://playground.arduino.cc/S1D15G10NokiaLCD/S1D15G10NokiaLCD Буду ее пробовать и паралельно в протеусе попробую свой код прогнать через логический анализатор.