LCD for 9XR board
LCD for 9XR board
Hi,guys,
Would like to know if anyone else can help solve my problem. I already asked for help on rcgroups.com and rcdesign.ru, but no one gave a clear answer . The fact is that I'm trying to hook up the display to 9XR motherboard. Turnkey solutions already exist
http://www.rcgroups.com/forums/showpost ... tcount=907,
but this display
http://www.ebay.com/itm/12864-128X64-Gr ... OC:DE:3160
is much smaller than the original . I found this one.
But when it is connected to the board a strange thing happens - the image is divided horizontally into two parts and they change places - the bottom half is on top and the top - on the bottom.
I have 3 LCDs and 3 motherboards with different firmware (9XR, er9x and openTx), I've tried to connect them randomly , but the result is the same. Unfortunately , I'm not a programmer ( nobody is perfect ...). In the datasheet of the display http://www.egochina.net.cn/e-shop/ebay/ ... JHD756.pdf there is an initialization instruction, but I don't know where insert it into lcd.cpp file.
Here in the forum there are so many smart people - I hope they help...
Would like to know if anyone else can help solve my problem. I already asked for help on rcgroups.com and rcdesign.ru, but no one gave a clear answer . The fact is that I'm trying to hook up the display to 9XR motherboard. Turnkey solutions already exist
http://www.rcgroups.com/forums/showpost ... tcount=907,
but this display
http://www.ebay.com/itm/12864-128X64-Gr ... OC:DE:3160
is much smaller than the original . I found this one.
But when it is connected to the board a strange thing happens - the image is divided horizontally into two parts and they change places - the bottom half is on top and the top - on the bottom.
I have 3 LCDs and 3 motherboards with different firmware (9XR, er9x and openTx), I've tried to connect them randomly , but the result is the same. Unfortunately , I'm not a programmer ( nobody is perfect ...). In the datasheet of the display http://www.egochina.net.cn/e-shop/ebay/ ... JHD756.pdf there is an initialization instruction, but I don't know where insert it into lcd.cpp file.
Here in the forum there are so many smart people - I hope they help...
- MikeB
- 9x Developer
- Posts: 18000
- Joined: Tue Dec 27, 2011 1:24 pm
- Country: -
- Location: Poole, Dorset, UK
Re: LCD for 9XR board
If you can build er9x, try the following change:
0x40 added to init codes, 12 changed to 13 in the for instruction.
Mike.
Code: Select all
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0x40, 0xAF
} ;
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
uint8_t i ;
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for ( i = 0 ; i < 13 ; i += 1 )
Mike.
erskyTx/er9x developer
The difficult we do immediately,
The impossible takes a little longer!
The difficult we do immediately,
The impossible takes a little longer!
Re: LCD for 9XR board
Hi Mike,
Sorry for the delay in replying . I haven't good news yet. I 've never really built the program, has always enjoyed the finished product . Well, everything in this life is ever done for the first time ...
So I tried to insert a block of your code in existing lcd.cpp file using avrstudio, like this
and replace the entire piece of initialize display, like this
then built er9.hex by clicking er9x-builder ( right?) it seems the program is compiled
and flash transmitter .
Nothing changes , the image remains divided into two halves. Yesterday arrived small displays, and they work out of the box. What drive me wild is that they are completely identical to the parameters , but small ones works and big ones - no.
What can I do , Mike?
Sorry for the delay in replying . I haven't good news yet. I 've never really built the program, has always enjoyed the finished product . Well, everything in this life is ever done for the first time ...
So I tried to insert a block of your code in existing lcd.cpp file using avrstudio, like this
Code: Select all
/*
* Author - Erez Raviv <[email protected]>
*
* Based on th9x -> http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "er9x.h"
#include <stdlib.h>
//#define LCD_2_CS 1
#define DBL_FONT_SMALL 1
#ifdef SIMU
bool lcd_refresh = true;
uint8_t lcd_buf[DISPLAY_W*DISPLAY_H/8];
#endif
uint8_t lcd_lastPos;
uint8_t displayBuf[DISPLAY_W*DISPLAY_H/8];
#define DISPLAY_END (displayBuf+sizeof(displayBuf))
const prog_uchar APM font[] = {
#include "font.lbm"
};
#define font_5x8_x20_x7f (font)
const prog_uchar APM font_dblsize[] = {
#include "font_dblsize.lbm"
};
#define font_10x16_x20_x7f (font_dblsize)
void lcd_clear()
{
//for(unsigned i=0; i<sizeof(displayBuf); i++) displayBuf[i]=0;
memset(displayBuf, 0, sizeof(displayBuf));
}
void lcd_img(uint8_t i_x,uint8_t i_y,const prog_uchar * imgdat,uint8_t idx/*,uint8_t mode*/)
{
const prog_uchar *q = imgdat;
uint8_t w = pgm_read_byte(q++);
uint8_t hb = (pgm_read_byte(q++)+7)/8;
uint8_t sze1 = pgm_read_byte(q++);
q += idx*sze1;
// bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
for(uint8_t yb = 0; yb < hb; yb++){
uint8_t *p = &displayBuf[ (i_y / 8 + yb) * DISPLAY_W + i_x ];
for(uint8_t x=0; x < w; x++){
uint8_t b = pgm_read_byte(q++);
*p++ = b;
//*p++ = inv ? ~b : b;
}
}
}
uint8_t lcd_putc(uint8_t x,uint8_t y,const char c)
{
return lcd_putcAtt(x,y,c,0);
}
/// invers: 0 no 1=yes 2=blink
uint8_t lcd_putcAtt(uint8_t x,uint8_t y,const char c,uint8_t mode)
{
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
//uint8_t *pmax = &displayBuf[ DISPLAY_H/8 * DISPLAY_W ];
if ( c < 22 ) // Move to specific x position (c)*FW
{
x = c * FW ;
// if(mode&DBLSIZE)
// {
// x += x ;
// }
return x ;
}
x += FW ;
const prog_uchar *q = &font_5x8_x20_x7f[(c-0x20)*5];
bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
if(mode&DBLSIZE)
{
if ( (c!=0x2E)) x+=FW; //check for decimal point
/* each letter consists of ten top bytes followed by
* five bottom by ten bottom bytes (20 bytes per
* char) */
unsigned char c_mapped ;
#ifdef DBL_FONT_SMALL
if ( c >= ',' && c <= ':' )
{
c_mapped = c - ',' + 1 ;
}
else if (c>='A' && c<='Z')
{
c_mapped = c - 'A' + 0x10 ;
}
else if (c>='a' && c<='z')
{
c_mapped = c - 'a' + 0x2B ;
}
else if (c=='_' )
{
c_mapped = 0x2A ;
}
else
{
c_mapped = 0 ;
}
#else
c_mapped = c - 0x20 ;
#endif
q = &font_10x16_x20_x7f[(c_mapped)*20] ;// + ((c-0x20)/16)*160];
for(char i=11; i>=0; i--){
/*top byte*/
uint8_t b1 = i>1 ? pgm_read_byte(q) : 0;
/*bottom byte*/
uint8_t b3 = i>1 ? pgm_read_byte(10+q) : 0;
/*top byte*/
// uint8_t b2 = i>0 ? pgm_read_byte(++q) : 0;
/*bottom byte*/
// uint8_t b4 = i>0 ? pgm_read_byte(10+q) : 0;
q++;
if(inv) {
b1=~b1;
// b2=~b2;
b3=~b3;
// b4=~b4;
}
if(&p[DISPLAY_W+1] < DISPLAY_END){
p[0]=b1;
// p[1]=b2;
p[DISPLAY_W] = b3;
// p[DISPLAY_W+1] = b4;
p+=1;
}
}
// q = &dbl_font[(c-0x20)*20];
// for(char i=0; i<10; i++){
// uint8_t b = pgm_read_byte(q++);
// if((p+DISPLAY_W)<DISPLAY_END) *(p+DISPLAY_W) = inv ? ~b : b;
// b = pgm_read_byte(q++);
// if(p<DISPLAY_END) *p = inv ? ~b : b;
// p++;
// }
// if(p<DISPLAY_END) *p = inv ? ~0 : 0;
// if((p+DISPLAY_W)<DISPLAY_END) *(p+DISPLAY_W) = inv ? ~0 : 0;
}
else
{
uint8_t condense=0;
if (mode & CONDENSED) {
*p = inv ? ~0 : 0;
p += 1 ;
condense=1;
x += FWNUM-FW ;
}
for(char i=5; i!=0; i--){
uint8_t b = pgm_read_byte(q++);
if (condense && i==4) {
/*condense the letter by skipping column 4 */
continue;
}
if(p<DISPLAY_END) {*p = inv ? ~b : b; p += 1 ; }
}
if(p<DISPLAY_END) *p++ = inv ? ~0 : 0;
}
return x ;
}
// Puts sub-string from string options
// First byte of string is sub-string length
// idx is index into string (in length units)
// Output length characters
void lcd_putsAttIdx(uint8_t x,uint8_t y,const prog_char * s,uint8_t idx,uint8_t att)
{
uint8_t length ;
length = pgm_read_byte(s++) ;
lcd_putsnAtt(x,y,s+length*idx,length,att) ;
}
//uint8_t lcd_putsnAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t len,uint8_t mode)
void lcd_putsnAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t len,uint8_t mode)
{
uint8_t source ;
// uint8_t size ;
source = mode & BSS ;
// size = mode & DBLSIZE ;
while(len!=0) {
char c = (source) ? *s++ : pgm_read_byte(s++);
x = lcd_putcAtt(x,y,c,mode);
// x+=FW;
// if ((size)&& (c!=0x2E)) x+=FW; //check for decimal point
len--;
}
}
void lcd_putsn_P(uint8_t x,uint8_t y,const prog_char * s,uint8_t len)
{
lcd_putsnAtt( x,y,s,len,0);
}
//uint8_t lcd_puts2Att(uint8_t x,uint8_t y,const prog_char * s,const prog_char * t ,uint8_t mode)
//{
// x = lcd_putsAtt( x, y, s, mode ) ;
// return lcd_putsAtt( x, y, t, mode ) ;
//}
uint8_t lcd_putsAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t mode)
{
uint8_t source ;
// uint8_t size ;
source = mode & BSS ;
// size = mode & DBLSIZE ;
//while(char c=pgm_read_byte(s++)) {
while(1) {
char c = (source) ? *s++ : pgm_read_byte(s++);
if(!c) break;
x = lcd_putcAtt(x,y,c,mode);
// x+=FW;
// if ((size)&& (c!=0x2E)) x+=FW; //check for decimal point
}
return x;
}
void lcd_puts_Pleft(uint8_t y,const prog_char * s)
{
lcd_putsAtt( 0, y, s, 0);
}
void lcd_puts_P(uint8_t x,uint8_t y,const prog_char * s)
{
lcd_putsAtt( x, y, s, 0);
}
void lcd_outhex4(uint8_t x,uint8_t y,uint16_t val)
{
x+=FWNUM*4;
for(int i=0; i<4; i++)
{
x-=FWNUM;
char c = val & 0xf;
c = c>9 ? c+'A'-10 : c+'0';
lcd_putcAtt(x,y,c,c>='A'?CONDENSED:0);
val>>=4;
}
}
void lcd_outdez(uint8_t x,uint8_t y,int16_t val)
{
lcd_outdezAtt(x,y,val,0);
}
void lcd_outdezAtt(uint8_t x,uint8_t y,int16_t val,uint8_t mode)
{
lcd_outdezNAtt( x,y,val,mode,5);
}
#define PREC(n) ((n&0x20) ? ((n&0x10) ? 2 : 1) : 0)
uint8_t lcd_outdezNAtt(uint8_t x,uint8_t y,int32_t val,uint8_t mode,int8_t len)
{
uint8_t fw = FWNUM;
uint8_t prec = PREC(mode);
uint8_t negative = 0 ;
uint8_t xn = 0;
uint8_t ln = 2;
char c;
uint8_t xinc ;
uint8_t fullwidth = 0 ;
mode &= ~NO_UNIT ;
if ( len < 0 )
{
fullwidth = 1 ;
len = -len ;
}
if ( val < 0 )
{
val = -val ;
negative = 1 ;
}
if (mode & DBLSIZE)
{
fw += FWNUM ;
xinc = 2*FWNUM;
lcd_lastPos = 2*FW;
}
else
{
xinc = FWNUM ;
lcd_lastPos = FW;
}
if (mode & LEFT) {
// if (val >= 10000)
// x += fw;
if(negative)
{
x += fw;
}
if (val >= 1000)
x += fw;
if (val >= 100)
x += fw;
if (val >= 10)
x += fw;
if ( prec )
{
if ( prec == 2 )
{
if ( val < 100 )
{
x += fw;
}
}
if ( val < 10 )
{
x+= fw;
}
}
}
else
{
x -= xinc;
}
lcd_lastPos += x ;
if ( prec == 2 )
{
mode -= LEADING0; // Can't have PREC2 and LEADING0
}
for (uint8_t i=1; i<=len; i++)
{
div_t qr ;
qr = div( val, 10 ) ;
c = (qr.rem) + '0';
lcd_putcAtt(x, y, c, mode);
if (prec==i) {
if (mode & DBLSIZE) {
xn = x;
if( c<='3' && c>='1') ln++;
uint8_t tn = (qr.quot) % 10;
if(tn==2 || tn==4) {
if (c=='4') {
xn++;
}
else {
xn--; ln++;
}
}
}
else {
x -= 2;
if (mode & INVERS)
lcd_vline(x+1, y, 7);
else
lcd_plot(x+1, y+6);
}
if (qr.quot)
prec = 0;
}
val = qr.quot ;
if (!val)
{
if (prec)
{
if ( prec == 2 )
{
if ( i > 1 )
{
prec = 0 ;
}
}
else
{
prec = 0 ;
}
}
else if (mode & LEADING0)
{
if ( fullwidth == 0 )
{
mode -= LEADING0;
}
}
else
break;
}
x-=fw;
}
if (xn) {
lcd_hline(xn, y+2*FH-4, ln);
lcd_hline(xn, y+2*FH-3, ln);
}
if(negative) lcd_putcAtt(x-fw,y,'-',mode);
return 0 ; // Stops compiler creating two sets of POPS, saves flash
}
void lcd_hbar( uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t percent )
{
uint8_t solid ;
if ( percent > 100 )
{
percent = 100 ;
}
solid = (w-2) * percent / 100 ;
lcd_rect( x, y, w, h ) ;
if ( solid )
{
w = y + h - 1 ;
y += 1 ;
x += 1 ;
while ( y < w )
{
lcd_hline(x, y, solid ) ;
y += 1 ;
}
}
}
// Reverse video 8 pixels high, w pixels wide
// Vertically on an 8 pixel high boundary
void lcd_char_inverse( uint8_t x, uint8_t y, uint8_t w, uint8_t blink )
{
if ( blink && BLINK_ON_PHASE )
{
return ;
}
uint8_t end = x + w ;
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
while ( x < end )
{
*p++ ^= 0xFF ;
x += 1 ;
}
}
void lcd_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h )
{
lcd_vline(x, y, h ) ;
if ( w > 1 )
{
lcd_vline(x+w-1, y, h ) ;
}
lcd_hline(x+1, y+h-1, w-2 ) ;
lcd_hline(x+1, y, w-2 ) ;
}
void lcd_plot(uint8_t x,uint8_t y)
{
// if(y>=64) return;
// if(x>=128) return;
// displayBuf[ y / 8 * DISPLAY_W + x ] ^= BITMASK(y%8);
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
if(p<DISPLAY_END) *p ^= BITMASK(y%8);
}
void lcd_hlineStip(unsigned char x,unsigned char y, signed char w,uint8_t pat)
{
if(w<0) {x+=w; w=-w;}
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
uint8_t msk = BITMASK(y%8);
while(w){
if ( p>=DISPLAY_END)
{
break ;
}
if(pat&1) {
//lcd_plot(x,y);
*p ^= msk;
pat = (pat >> 1) | 0x80;
}else{
pat = pat >> 1;
}
w--;
p++;
}
}
void lcd_hline(uint8_t x,uint8_t y, int8_t w)
{
lcd_hlineStip(x,y,w,0xff);
}
void lcd_vline(uint8_t x,uint8_t y, int8_t h)
{
// while ((y+h)>=DISPLAY_H) h--;
uint8_t y1 ;
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
y1 = y + h ;
uint8_t *q = &displayBuf[ y1 / 8 * DISPLAY_W + x ];
*p ^= ~(BITMASK(y%8)-1);
while(p<q){
p += DISPLAY_W;
if ( p>=DISPLAY_END)
{
break ;
}
*p ^= 0xff;
}
if(p<DISPLAY_END) *p ^= ~(BITMASK((y+h)%8)-1);
}
#if LCD_OTHER
// Supports 4W serial LCD interface and SSD1306 OLED controller
// - Hyun-Taek Chang ([email protected]), Feb 2013
// to select either stock LCD controller or SSD1306 OLED controller
#define SSD1306 0 // Stock(ST7565/NT7532)=0, SSD1306=1
// controller independent options
#define SERIAL_LCD 0 // parallel=0, 4W_serial=1
#define ROTATE_SCREEN 0 // don't-rotate-screen=0, rotate-180-degree=1
#define REVERSE_VIDEO 0 // don't-reverse-video=0, reverse-video=1
#if (SSD1306 || ROTATE_SCREEN)
#define COLUMN_START_LO 0x00
#else // ST7565
#define COLUMN_START_LO 0x04 // skip first 4 columns
#endif
#if (SSD1306 || ROTATE_SCREEN)
#define COLUMN_START_LO 0x00
#else // ST7565
#define COLUMN_START_LO 0x04 // skip first 4 columns
#endif
// force inline expansion
#define ALWAYS_INLINE __attribute__((always_inline))
static void lcdSendByte(uint8_t val, uint8_t v0, uint8_t v1) ALWAYS_INLINE;
static void lcdEndSend() ALWAYS_INLINE;
static void lcdEndSend()
{
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1); // disable chip select
}
#if SERIAL_LCD
// Serial LCD module's SCLK(clock) and SI(data) must be connected
// to Atmega's PC4 and PC5, respectively.
#define OUT_C_LCD_SCL OUT_C_LCD_RnW // PC4
#define OUT_C_LCD_SI OUT_C_LCD_E // PC5
static void lcdSendBit(uint8_t b, uint8_t v0, uint8_t v1) ALWAYS_INLINE;
// NOTE: ST7565 SCLK min period is 50ns (100ns?)
// single bit write takes 5 cycles = 312.5ns @16MHz clock
static void lcdSendBit(uint8_t b, uint8_t v0, uint8_t v1)
{
PORTC_LCD_CTRL = v0; // out 0x15, r19 ; 1 cycle
if (b != 0) // sbrc r24, 7 ; 1 cycle
PORTC_LCD_CTRL = v1; // out 0x15, r18 ; 1 cycle
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_SCL); // sbi 0x15, 4 ; 2 cycles
}
static void lcdSendByte(uint8_t val, uint8_t v0, uint8_t v1)
{
lcdSendBit((val & 0x80), v0, v1);
lcdSendBit((val & 0x40), v0, v1);
lcdSendBit((val & 0x20), v0, v1);
lcdSendBit((val & 0x10), v0, v1);
lcdSendBit((val & 0x08), v0, v1);
lcdSendBit((val & 0x04), v0, v1);
lcdSendBit((val & 0x02), v0, v1);
lcdSendBit((val & 0x01), v0, v1);
}
static void lcdSendCtl(uint8_t val)
{
uint8_t v0c = 0xC5; // PC7=1,PC6=1,SI=0,SCL=0,A0=0,RES=1,CS1=0,PC0=1
uint8_t v1c = 0xE5; // PC7=1,PC6=1,SI=1,SCL=0,A0=0,RES=1,CS1=0,PC0=1
for (uint8_t n = 8; n > 0; n--) {
lcdSendBit((val & 0x80), v0c, v1c);
val <<= 1;
}
lcdEndSend();
}
#else // PARALLEL_LCD
static void lcdStartSend() ALWAYS_INLINE;
static void lcdStartSend()
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1); // enable chip select
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); // enable write
}
static void lcdSendByte(uint8_t val, uint8_t = 0, uint8_t = 0)
{
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E); // rise enable
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E); // fall enable
}
static void lcdSendCtl(uint8_t val)
{
lcdStartSend();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0); // set to control mode
lcdSendByte(val);
lcdEndSend();
}
#endif
#define delay_1us() _delay_us(1)
#define delay_2us() _delay_us(2)
static void delay_1_5us(int ms)
{
for(int i=0; i<ms; i++) delay_1us();
}
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0x40, 0xAF
} ;
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
uint8_t i ;
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for ( i = 0 ; i < 13 ; i += 1 )
}
const static prog_uchar APM Lcdinit[] =
{
#if SSD1306
0xAE, // DON = 0: display OFF
0xD5, 0x80, // set display clock 100 frames/sec
0xA8, 0x3F, // set multiplex ratio 1/64 duty
0xD3, 0x00, // set display offset 0
# if EXTERNAL_VCC
0x8D, 0x10, // disable embedded DC/DC converter
0xD9, 0x22, // set precharge, discharge 2 clocks each
# else
0x8D, 0x14, // enable embedded DC/DC conveter
0xD9, 0xF1, // set precharge 15 clocks, discharge 1 clock
# endif
0xDA, 0x12, // set COM pins hardware configuration
0xDB, 0x40, // set VCOMH deselect level -undocumented
# if ROTATE_SCREEN
0xA1, // ADC = 1: reverse direction(SEG128->SEG1)
0xC8, // SHL = 1: reverse direction (COM64->COM1)
# else
0xA0, // ADC = 0: normal direction(SEG1->SEG128)
0xC0, // SHL = 0: normal direction (COM1->COM64)
# endif
#else // !SSD1306 == ST7565 (stock LCD controller)
0xE2, // Initialize the internal functions
0xAE, // DON = 0: display OFF
0xA4, // Disable entire display-ON
0xA2, // Select LCD bias=0
0x2F, // Control power circuit operation VC=VR=VF=1
0x25, // Select int resistance ratio R2 R1 R0 =5
# if ROTATE_SCREEN
0xA0, // ADC = 0: normal direction(SEG1->SEG132/SEG128)
0xC8, // SHL = 1: reverse direction (COM64->COM1)
# else
0xA1, // ADC = 1: reverse direction(SEG132/SEG128->SEG1)
0xC0, // SHL = 0: normal direction (COM1->COM64)
# endif
#endif // SSD1306
#if REVERSE_VIDEO
0xA7, // REV = 1: reverse display
#else
0xA6, // REV = 0: non-reverse display
#endif // REVERSE_VIDEO
0xAF // DON = 1: display ON
};
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for (uint8_t i = 0; i < sizeof(Lcdinit); i++) {
lcdSendCtl(pgm_read_byte(&Lcdinit[i]));
}
g_eeGeneral.contrast = lcd_nomContrast;
LcdLock = 0 ; // Free LCD data lines
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
void refreshDiplay()
{
#ifdef SIMU
memcpy(lcd_buf, displayBuf, sizeof(displayBuf));
lcd_refresh = true;
#else
LcdLock = 1 ; // Lock LCD data lines
uint8_t *p=displayBuf;
#if SERIAL_LCD
const uint8_t v0c = 0xC5; // PC7=1,PC6=1,SI=0,SCL=0,A0=0,RES=1,CS1=0,PC0=1
const uint8_t v1c = 0xE5; // PC7=1,PC6=1,SI=1,SCL=0,A0=0,RES=1,CS1=0,PC0=1
const uint8_t v0d = 0xCD; // PC7=1,PC6=1,SI=0,SCL=0,A0=1,RES=1,CS1=0,PC0=1
const uint8_t v1d = 0xED; // PC7=1,PC6=1,SI=1,SCL=0,A0=1,RES=1,CS1=0,PC0=1
for(uint8_t y=0xB0; y < 0xB8; y++) {
lcdSendByte(COLUMN_START_LO, v0c, v1c);
lcdSendByte(0x10, v0c, v1c); //column addr 0
lcdSendByte(y, v0c, v1c); //page addr y
for(uint8_t x=32; x>0; x--){
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
}
}
#else
lcdStartSend();
for(uint8_t y=0xB0; y < 0xB8; y++) {
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0); // switch to ctl send mode
lcdSendByte(COLUMN_START_LO);
lcdSendByte(0x10); //column addr 0
lcdSendByte(y); //page addr y
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); // switch to data send mode
for(uint8_t x=32; x>0; x--){
lcdSendByte(*p++);
lcdSendByte(*p++);
lcdSendByte(*p++);
lcdSendByte(*p++);
}
}
#endif
lcdEndSend();
LcdLock = 0 ; // Free LCD data lines
#endif
}
#else // !defined(LCD_OTHER)
#ifndef LCD_2_CS
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
#define delay_1us() _delay_us(1)
#define delay_2us() _delay_us(2)
static void delay_1_5us( uint16_t ms)
{
for( uint16_t i=0; i<ms; i++) delay_1us();
}
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0xAF
} ;
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
uint8_t i ;
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for ( i = 0 ; i < 12 ; i += 1 )
{
lcdSendCtl(pgm_read_byte(&Lcdinit[i]) ) ;
}
g_eeGeneral.contrast = lcd_nomContrast ;
LcdLock = 0 ; // Free LCD data lines
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
//volatile uint8_t LcdTrims ;
//uint8_t LcdTrimSwapped ;
void refreshDiplay()
{
#ifdef SIMU
memcpy(lcd_buf, displayBuf, sizeof(displayBuf));
lcd_refresh = true;
#else
LcdLock = 1 ; // Lock LCD data lines
uint8_t *p=displayBuf;
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0x04);
lcdSendCtl(0x10); //column addr 0
lcdSendCtl( y | 0xB0); //page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for(uint8_t x=32; x>0; x--){
// lcdSendDat(*p);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
// p++;
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
LcdLock = 0 ; // Free LCD data lines
#endif
}
#endif
#ifdef LCD_2_CS
uint8_t toggle_e()
{
uint8_t value ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E) ;
asm("rjmp .+0") ;
asm("rjmp .+0") ;
asm("nop") ;
value = PINA ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E) ;
return value ;
}
#define delay_1us() _delay_us(1)
void delay_1_5us(int ms)
{
for(int i=0; i<ms; i++) delay_1us();
}
#define OUT_C_LCD_CS2 0
static void lcdSendCtl(uint8_t val)
{
uint8_t busy ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
}
uint8_t Hpos ;
static void lcdSendDat(uint8_t val)
{
uint8_t busy ;
if ( Hpos )
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1) ;
}
else
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2) ;
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
}
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_1us();
delay_1us();// f520 call 0xf4ce delay_1us() ; 0x0xf4ce
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
lcdSendCtl(0xC0); //
lcdSendCtl(0x3F); //DON = 1: display ON
g_eeGeneral.contrast = 0x22;
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
//volatile uint8_t LcdTrims ;
//uint8_t LcdTrimSwapped ;
void refreshDiplay()
{
uint8_t *p=displayBuf;
LcdLock = 1 ; // Lock LCD data lines
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0xC0); //
lcdSendCtl(0x40); //column addr 0
lcdSendCtl( y | 0xB8); //page addr y
for(uint8_t x=0; x<128; x++)
{
Hpos = x & 64 ;
lcdSendDat(*p);
p++;
}
// PORTA = 0xFF; // Outputs high/pullups enabled
}
LcdLock = 0 ; // Free LCD data lines
}
#endif
#endif // LCD_OTHER
Code: Select all
/*
* Author - Erez Raviv <[email protected]>
*
* Based on th9x -> http://code.google.com/p/th9x/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include "er9x.h"
#include <stdlib.h>
//#define LCD_2_CS 1
#define DBL_FONT_SMALL 1
#ifdef SIMU
bool lcd_refresh = true;
uint8_t lcd_buf[DISPLAY_W*DISPLAY_H/8];
#endif
uint8_t lcd_lastPos;
uint8_t displayBuf[DISPLAY_W*DISPLAY_H/8];
#define DISPLAY_END (displayBuf+sizeof(displayBuf))
const prog_uchar APM font[] = {
#include "font.lbm"
};
#define font_5x8_x20_x7f (font)
const prog_uchar APM font_dblsize[] = {
#include "font_dblsize.lbm"
};
#define font_10x16_x20_x7f (font_dblsize)
void lcd_clear()
{
//for(unsigned i=0; i<sizeof(displayBuf); i++) displayBuf[i]=0;
memset(displayBuf, 0, sizeof(displayBuf));
}
void lcd_img(uint8_t i_x,uint8_t i_y,const prog_uchar * imgdat,uint8_t idx/*,uint8_t mode*/)
{
const prog_uchar *q = imgdat;
uint8_t w = pgm_read_byte(q++);
uint8_t hb = (pgm_read_byte(q++)+7)/8;
uint8_t sze1 = pgm_read_byte(q++);
q += idx*sze1;
// bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
for(uint8_t yb = 0; yb < hb; yb++){
uint8_t *p = &displayBuf[ (i_y / 8 + yb) * DISPLAY_W + i_x ];
for(uint8_t x=0; x < w; x++){
uint8_t b = pgm_read_byte(q++);
*p++ = b;
//*p++ = inv ? ~b : b;
}
}
}
uint8_t lcd_putc(uint8_t x,uint8_t y,const char c)
{
return lcd_putcAtt(x,y,c,0);
}
/// invers: 0 no 1=yes 2=blink
uint8_t lcd_putcAtt(uint8_t x,uint8_t y,const char c,uint8_t mode)
{
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
//uint8_t *pmax = &displayBuf[ DISPLAY_H/8 * DISPLAY_W ];
if ( c < 22 ) // Move to specific x position (c)*FW
{
x = c * FW ;
// if(mode&DBLSIZE)
// {
// x += x ;
// }
return x ;
}
x += FW ;
const prog_uchar *q = &font_5x8_x20_x7f[(c-0x20)*5];
bool inv = (mode & INVERS) ? true : (mode & BLINK ? BLINK_ON_PHASE : false);
if(mode&DBLSIZE)
{
if ( (c!=0x2E)) x+=FW; //check for decimal point
/* each letter consists of ten top bytes followed by
* five bottom by ten bottom bytes (20 bytes per
* char) */
unsigned char c_mapped ;
#ifdef DBL_FONT_SMALL
if ( c >= ',' && c <= ':' )
{
c_mapped = c - ',' + 1 ;
}
else if (c>='A' && c<='Z')
{
c_mapped = c - 'A' + 0x10 ;
}
else if (c>='a' && c<='z')
{
c_mapped = c - 'a' + 0x2B ;
}
else if (c=='_' )
{
c_mapped = 0x2A ;
}
else
{
c_mapped = 0 ;
}
#else
c_mapped = c - 0x20 ;
#endif
q = &font_10x16_x20_x7f[(c_mapped)*20] ;// + ((c-0x20)/16)*160];
for(char i=11; i>=0; i--){
/*top byte*/
uint8_t b1 = i>1 ? pgm_read_byte(q) : 0;
/*bottom byte*/
uint8_t b3 = i>1 ? pgm_read_byte(10+q) : 0;
/*top byte*/
// uint8_t b2 = i>0 ? pgm_read_byte(++q) : 0;
/*bottom byte*/
// uint8_t b4 = i>0 ? pgm_read_byte(10+q) : 0;
q++;
if(inv) {
b1=~b1;
// b2=~b2;
b3=~b3;
// b4=~b4;
}
if(&p[DISPLAY_W+1] < DISPLAY_END){
p[0]=b1;
// p[1]=b2;
p[DISPLAY_W] = b3;
// p[DISPLAY_W+1] = b4;
p+=1;
}
}
// q = &dbl_font[(c-0x20)*20];
// for(char i=0; i<10; i++){
// uint8_t b = pgm_read_byte(q++);
// if((p+DISPLAY_W)<DISPLAY_END) *(p+DISPLAY_W) = inv ? ~b : b;
// b = pgm_read_byte(q++);
// if(p<DISPLAY_END) *p = inv ? ~b : b;
// p++;
// }
// if(p<DISPLAY_END) *p = inv ? ~0 : 0;
// if((p+DISPLAY_W)<DISPLAY_END) *(p+DISPLAY_W) = inv ? ~0 : 0;
}
else
{
uint8_t condense=0;
if (mode & CONDENSED) {
*p = inv ? ~0 : 0;
p += 1 ;
condense=1;
x += FWNUM-FW ;
}
for(char i=5; i!=0; i--){
uint8_t b = pgm_read_byte(q++);
if (condense && i==4) {
/*condense the letter by skipping column 4 */
continue;
}
if(p<DISPLAY_END) {*p = inv ? ~b : b; p += 1 ; }
}
if(p<DISPLAY_END) *p++ = inv ? ~0 : 0;
}
return x ;
}
// Puts sub-string from string options
// First byte of string is sub-string length
// idx is index into string (in length units)
// Output length characters
void lcd_putsAttIdx(uint8_t x,uint8_t y,const prog_char * s,uint8_t idx,uint8_t att)
{
uint8_t length ;
length = pgm_read_byte(s++) ;
lcd_putsnAtt(x,y,s+length*idx,length,att) ;
}
//uint8_t lcd_putsnAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t len,uint8_t mode)
void lcd_putsnAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t len,uint8_t mode)
{
uint8_t source ;
// uint8_t size ;
source = mode & BSS ;
// size = mode & DBLSIZE ;
while(len!=0) {
char c = (source) ? *s++ : pgm_read_byte(s++);
x = lcd_putcAtt(x,y,c,mode);
// x+=FW;
// if ((size)&& (c!=0x2E)) x+=FW; //check for decimal point
len--;
}
}
void lcd_putsn_P(uint8_t x,uint8_t y,const prog_char * s,uint8_t len)
{
lcd_putsnAtt( x,y,s,len,0);
}
//uint8_t lcd_puts2Att(uint8_t x,uint8_t y,const prog_char * s,const prog_char * t ,uint8_t mode)
//{
// x = lcd_putsAtt( x, y, s, mode ) ;
// return lcd_putsAtt( x, y, t, mode ) ;
//}
uint8_t lcd_putsAtt(uint8_t x,uint8_t y,const prog_char * s,uint8_t mode)
{
uint8_t source ;
// uint8_t size ;
source = mode & BSS ;
// size = mode & DBLSIZE ;
//while(char c=pgm_read_byte(s++)) {
while(1) {
char c = (source) ? *s++ : pgm_read_byte(s++);
if(!c) break;
x = lcd_putcAtt(x,y,c,mode);
// x+=FW;
// if ((size)&& (c!=0x2E)) x+=FW; //check for decimal point
}
return x;
}
void lcd_puts_Pleft(uint8_t y,const prog_char * s)
{
lcd_putsAtt( 0, y, s, 0);
}
void lcd_puts_P(uint8_t x,uint8_t y,const prog_char * s)
{
lcd_putsAtt( x, y, s, 0);
}
void lcd_outhex4(uint8_t x,uint8_t y,uint16_t val)
{
x+=FWNUM*4;
for(int i=0; i<4; i++)
{
x-=FWNUM;
char c = val & 0xf;
c = c>9 ? c+'A'-10 : c+'0';
lcd_putcAtt(x,y,c,c>='A'?CONDENSED:0);
val>>=4;
}
}
void lcd_outdez(uint8_t x,uint8_t y,int16_t val)
{
lcd_outdezAtt(x,y,val,0);
}
void lcd_outdezAtt(uint8_t x,uint8_t y,int16_t val,uint8_t mode)
{
lcd_outdezNAtt( x,y,val,mode,5);
}
#define PREC(n) ((n&0x20) ? ((n&0x10) ? 2 : 1) : 0)
uint8_t lcd_outdezNAtt(uint8_t x,uint8_t y,int32_t val,uint8_t mode,int8_t len)
{
uint8_t fw = FWNUM;
uint8_t prec = PREC(mode);
uint8_t negative = 0 ;
uint8_t xn = 0;
uint8_t ln = 2;
char c;
uint8_t xinc ;
uint8_t fullwidth = 0 ;
mode &= ~NO_UNIT ;
if ( len < 0 )
{
fullwidth = 1 ;
len = -len ;
}
if ( val < 0 )
{
val = -val ;
negative = 1 ;
}
if (mode & DBLSIZE)
{
fw += FWNUM ;
xinc = 2*FWNUM;
lcd_lastPos = 2*FW;
}
else
{
xinc = FWNUM ;
lcd_lastPos = FW;
}
if (mode & LEFT) {
// if (val >= 10000)
// x += fw;
if(negative)
{
x += fw;
}
if (val >= 1000)
x += fw;
if (val >= 100)
x += fw;
if (val >= 10)
x += fw;
if ( prec )
{
if ( prec == 2 )
{
if ( val < 100 )
{
x += fw;
}
}
if ( val < 10 )
{
x+= fw;
}
}
}
else
{
x -= xinc;
}
lcd_lastPos += x ;
if ( prec == 2 )
{
mode -= LEADING0; // Can't have PREC2 and LEADING0
}
for (uint8_t i=1; i<=len; i++)
{
div_t qr ;
qr = div( val, 10 ) ;
c = (qr.rem) + '0';
lcd_putcAtt(x, y, c, mode);
if (prec==i) {
if (mode & DBLSIZE) {
xn = x;
if( c<='3' && c>='1') ln++;
uint8_t tn = (qr.quot) % 10;
if(tn==2 || tn==4) {
if (c=='4') {
xn++;
}
else {
xn--; ln++;
}
}
}
else {
x -= 2;
if (mode & INVERS)
lcd_vline(x+1, y, 7);
else
lcd_plot(x+1, y+6);
}
if (qr.quot)
prec = 0;
}
val = qr.quot ;
if (!val)
{
if (prec)
{
if ( prec == 2 )
{
if ( i > 1 )
{
prec = 0 ;
}
}
else
{
prec = 0 ;
}
}
else if (mode & LEADING0)
{
if ( fullwidth == 0 )
{
mode -= LEADING0;
}
}
else
break;
}
x-=fw;
}
if (xn) {
lcd_hline(xn, y+2*FH-4, ln);
lcd_hline(xn, y+2*FH-3, ln);
}
if(negative) lcd_putcAtt(x-fw,y,'-',mode);
return 0 ; // Stops compiler creating two sets of POPS, saves flash
}
void lcd_hbar( uint8_t x, uint8_t y, uint8_t w, uint8_t h, uint8_t percent )
{
uint8_t solid ;
if ( percent > 100 )
{
percent = 100 ;
}
solid = (w-2) * percent / 100 ;
lcd_rect( x, y, w, h ) ;
if ( solid )
{
w = y + h - 1 ;
y += 1 ;
x += 1 ;
while ( y < w )
{
lcd_hline(x, y, solid ) ;
y += 1 ;
}
}
}
// Reverse video 8 pixels high, w pixels wide
// Vertically on an 8 pixel high boundary
void lcd_char_inverse( uint8_t x, uint8_t y, uint8_t w, uint8_t blink )
{
if ( blink && BLINK_ON_PHASE )
{
return ;
}
uint8_t end = x + w ;
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
while ( x < end )
{
*p++ ^= 0xFF ;
x += 1 ;
}
}
void lcd_rect(uint8_t x, uint8_t y, uint8_t w, uint8_t h )
{
lcd_vline(x, y, h ) ;
if ( w > 1 )
{
lcd_vline(x+w-1, y, h ) ;
}
lcd_hline(x+1, y+h-1, w-2 ) ;
lcd_hline(x+1, y, w-2 ) ;
}
void lcd_plot(uint8_t x,uint8_t y)
{
// if(y>=64) return;
// if(x>=128) return;
// displayBuf[ y / 8 * DISPLAY_W + x ] ^= BITMASK(y%8);
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
if(p<DISPLAY_END) *p ^= BITMASK(y%8);
}
void lcd_hlineStip(unsigned char x,unsigned char y, signed char w,uint8_t pat)
{
if(w<0) {x+=w; w=-w;}
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
uint8_t msk = BITMASK(y%8);
while(w){
if ( p>=DISPLAY_END)
{
break ;
}
if(pat&1) {
//lcd_plot(x,y);
*p ^= msk;
pat = (pat >> 1) | 0x80;
}else{
pat = pat >> 1;
}
w--;
p++;
}
}
void lcd_hline(uint8_t x,uint8_t y, int8_t w)
{
lcd_hlineStip(x,y,w,0xff);
}
void lcd_vline(uint8_t x,uint8_t y, int8_t h)
{
// while ((y+h)>=DISPLAY_H) h--;
uint8_t y1 ;
uint8_t *p = &displayBuf[ y / 8 * DISPLAY_W + x ];
y1 = y + h ;
uint8_t *q = &displayBuf[ y1 / 8 * DISPLAY_W + x ];
*p ^= ~(BITMASK(y%8)-1);
while(p<q){
p += DISPLAY_W;
if ( p>=DISPLAY_END)
{
break ;
}
*p ^= 0xff;
}
if(p<DISPLAY_END) *p ^= ~(BITMASK((y+h)%8)-1);
}
#if LCD_OTHER
// Supports 4W serial LCD interface and SSD1306 OLED controller
// - Hyun-Taek Chang ([email protected]), Feb 2013
// to select either stock LCD controller or SSD1306 OLED controller
#define SSD1306 0 // Stock(ST7565/NT7532)=0, SSD1306=1
// controller independent options
#define SERIAL_LCD 0 // parallel=0, 4W_serial=1
#define ROTATE_SCREEN 0 // don't-rotate-screen=0, rotate-180-degree=1
#define REVERSE_VIDEO 0 // don't-reverse-video=0, reverse-video=1
#if (SSD1306 || ROTATE_SCREEN)
#define COLUMN_START_LO 0x00
#else // ST7565
#define COLUMN_START_LO 0x04 // skip first 4 columns
#endif
#if (SSD1306 || ROTATE_SCREEN)
#define COLUMN_START_LO 0x00
#else // ST7565
#define COLUMN_START_LO 0x04 // skip first 4 columns
#endif
// force inline expansion
#define ALWAYS_INLINE __attribute__((always_inline))
static void lcdSendByte(uint8_t val, uint8_t v0, uint8_t v1) ALWAYS_INLINE;
static void lcdEndSend() ALWAYS_INLINE;
static void lcdEndSend()
{
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1); // disable chip select
}
#if SERIAL_LCD
// Serial LCD module's SCLK(clock) and SI(data) must be connected
// to Atmega's PC4 and PC5, respectively.
#define OUT_C_LCD_SCL OUT_C_LCD_RnW // PC4
#define OUT_C_LCD_SI OUT_C_LCD_E // PC5
static void lcdSendBit(uint8_t b, uint8_t v0, uint8_t v1) ALWAYS_INLINE;
// NOTE: ST7565 SCLK min period is 50ns (100ns?)
// single bit write takes 5 cycles = 312.5ns @16MHz clock
static void lcdSendBit(uint8_t b, uint8_t v0, uint8_t v1)
{
PORTC_LCD_CTRL = v0; // out 0x15, r19 ; 1 cycle
if (b != 0) // sbrc r24, 7 ; 1 cycle
PORTC_LCD_CTRL = v1; // out 0x15, r18 ; 1 cycle
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_SCL); // sbi 0x15, 4 ; 2 cycles
}
static void lcdSendByte(uint8_t val, uint8_t v0, uint8_t v1)
{
lcdSendBit((val & 0x80), v0, v1);
lcdSendBit((val & 0x40), v0, v1);
lcdSendBit((val & 0x20), v0, v1);
lcdSendBit((val & 0x10), v0, v1);
lcdSendBit((val & 0x08), v0, v1);
lcdSendBit((val & 0x04), v0, v1);
lcdSendBit((val & 0x02), v0, v1);
lcdSendBit((val & 0x01), v0, v1);
}
static void lcdSendCtl(uint8_t val)
{
uint8_t v0c = 0xC5; // PC7=1,PC6=1,SI=0,SCL=0,A0=0,RES=1,CS1=0,PC0=1
uint8_t v1c = 0xE5; // PC7=1,PC6=1,SI=1,SCL=0,A0=0,RES=1,CS1=0,PC0=1
for (uint8_t n = 8; n > 0; n--) {
lcdSendBit((val & 0x80), v0c, v1c);
val <<= 1;
}
lcdEndSend();
}
#else // PARALLEL_LCD
static void lcdStartSend() ALWAYS_INLINE;
static void lcdStartSend()
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1); // enable chip select
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW); // enable write
}
static void lcdSendByte(uint8_t val, uint8_t = 0, uint8_t = 0)
{
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E); // rise enable
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E); // fall enable
}
static void lcdSendCtl(uint8_t val)
{
lcdStartSend();
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0); // set to control mode
lcdSendByte(val);
lcdEndSend();
}
#endif
#define delay_1us() _delay_us(1)
#define delay_2us() _delay_us(2)
static void delay_1_5us(int ms)
{
for(int i=0; i<ms; i++) delay_1us();
}
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0x40, 0xAF
} ;
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
uint8_t i ;
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for ( i = 0 ; i < 13 ; i += 1 )
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
void refreshDiplay()
{
#ifdef SIMU
memcpy(lcd_buf, displayBuf, sizeof(displayBuf));
lcd_refresh = true;
#else
LcdLock = 1 ; // Lock LCD data lines
uint8_t *p=displayBuf;
#if SERIAL_LCD
const uint8_t v0c = 0xC5; // PC7=1,PC6=1,SI=0,SCL=0,A0=0,RES=1,CS1=0,PC0=1
const uint8_t v1c = 0xE5; // PC7=1,PC6=1,SI=1,SCL=0,A0=0,RES=1,CS1=0,PC0=1
const uint8_t v0d = 0xCD; // PC7=1,PC6=1,SI=0,SCL=0,A0=1,RES=1,CS1=0,PC0=1
const uint8_t v1d = 0xED; // PC7=1,PC6=1,SI=1,SCL=0,A0=1,RES=1,CS1=0,PC0=1
for(uint8_t y=0xB0; y < 0xB8; y++) {
lcdSendByte(COLUMN_START_LO, v0c, v1c);
lcdSendByte(0x10, v0c, v1c); //column addr 0
lcdSendByte(y, v0c, v1c); //page addr y
for(uint8_t x=32; x>0; x--){
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
lcdSendByte(*p++, v0d, v1d);
}
}
#else
lcdStartSend();
for(uint8_t y=0xB0; y < 0xB8; y++) {
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0); // switch to ctl send mode
lcdSendByte(COLUMN_START_LO);
lcdSendByte(0x10); //column addr 0
lcdSendByte(y); //page addr y
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0); // switch to data send mode
for(uint8_t x=32; x>0; x--){
lcdSendByte(*p++);
lcdSendByte(*p++);
lcdSendByte(*p++);
lcdSendByte(*p++);
}
}
#endif
lcdEndSend();
LcdLock = 0 ; // Free LCD data lines
#endif
}
#else // !defined(LCD_OTHER)
#ifndef LCD_2_CS
void lcdSendCtl(uint8_t val)
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
#define delay_1us() _delay_us(1)
#define delay_2us() _delay_us(2)
static void delay_1_5us( uint16_t ms)
{
for( uint16_t i=0; i<ms; i++) delay_1us();
}
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0xAF
} ;
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
uint8_t i ;
LcdLock = 1 ; // Lock LCD data lines
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_2us();
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
delay_1_5us(1500);
for ( i = 0 ; i < 12 ; i += 1 )
{
lcdSendCtl(pgm_read_byte(&Lcdinit[i]) ) ;
}
g_eeGeneral.contrast = lcd_nomContrast ;
LcdLock = 0 ; // Free LCD data lines
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
//volatile uint8_t LcdTrims ;
//uint8_t LcdTrimSwapped ;
void refreshDiplay()
{
#ifdef SIMU
memcpy(lcd_buf, displayBuf, sizeof(displayBuf));
lcd_refresh = true;
#else
LcdLock = 1 ; // Lock LCD data lines
uint8_t *p=displayBuf;
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0x04);
lcdSendCtl(0x10); //column addr 0
lcdSendCtl( y | 0xB0); //page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
for(uint8_t x=32; x>0; x--){
// lcdSendDat(*p);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
PORTA_LCD_DAT = *p++;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E);
// p++;
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
}
LcdLock = 0 ; // Free LCD data lines
#endif
}
#endif
#ifdef LCD_2_CS
uint8_t toggle_e()
{
uint8_t value ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_E) ;
asm("rjmp .+0") ;
asm("rjmp .+0") ;
asm("nop") ;
value = PINA ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_E) ;
return value ;
}
#define delay_1us() _delay_us(1)
void delay_1_5us(int ms)
{
for(int i=0; i<ms; i++) delay_1us();
}
#define OUT_C_LCD_CS2 0
static void lcdSendCtl(uint8_t val)
{
uint8_t busy ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
}
uint8_t Hpos ;
static void lcdSendDat(uint8_t val)
{
uint8_t busy ;
if ( Hpos )
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1) ;
}
else
{
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS2) ;
}
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RnW) ; // read
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_A0);
DDRA = 0 ;
do
{
busy = toggle_e() ;
} while ( busy & 0x80 ) ;
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RnW);
DDRA = 0xFF ;
PORTA_LCD_DAT = val;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
toggle_e() ;
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
}
void lcd_init()
{
// /home/thus/txt/datasheets/lcd/KS0713.pdf
// ~/txt/flieger/ST7565RV17.pdf from http://www.glyn.de/content.asp?wdid=132&sid=
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS1);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_CS2);
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_A0);
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_RES); //LCD_RES
delay_1us();
delay_1us();// f520 call 0xf4ce delay_1us() ; 0x0xf4ce
PORTC_LCD_CTRL |= (1<<OUT_C_LCD_RES); // f524 sbi 0x15, 2 IOADR-PORTC_LCD_CTRL; 21 1
lcdSendCtl(0xC0); //
lcdSendCtl(0x3F); //DON = 1: display ON
g_eeGeneral.contrast = 0x22;
}
void lcdSetContrast()
{
lcdSetRefVolt(g_eeGeneral.contrast);
}
void lcdSetRefVolt(uint8_t val)
{
LcdLock = 1 ; // Lock LCD data lines
lcdSendCtl(0x81);
lcdSendCtl(val);
LcdLock = 0 ; // Free LCD data lines
}
volatile uint8_t LcdLock ;
//volatile uint8_t LcdTrims ;
//uint8_t LcdTrimSwapped ;
void refreshDiplay()
{
uint8_t *p=displayBuf;
LcdLock = 1 ; // Lock LCD data lines
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0xC0); //
lcdSendCtl(0x40); //column addr 0
lcdSendCtl( y | 0xB8); //page addr y
for(uint8_t x=0; x<128; x++)
{
Hpos = x & 64 ;
lcdSendDat(*p);
p++;
}
// PORTA = 0xFF; // Outputs high/pullups enabled
}
LcdLock = 0 ; // Free LCD data lines
}
#endif
#endif // LCD_OTHER
Nothing changes , the image remains divided into two halves. Yesterday arrived small displays, and they work out of the box. What drive me wild is that they are completely identical to the parameters , but small ones works and big ones - no.
What can I do , Mike?
- MikeB
- 9x Developer
- Posts: 18000
- Joined: Tue Dec 27, 2011 1:24 pm
- Country: -
- Location: Poole, Dorset, UK
Re: LCD for 9XR board
You changed the wrong piece of code. That is some new code for handling a serial LCD.
Further down the file is the code you need to change.
Search down for:
already in the file. This is the area to change.
Mike.
Further down the file is the code you need to change.
Search down for:
Code: Select all
const static prog_uchar APM Lcdinit[] =
{
0xe2, 0xae, 0xa1, 0xA6, 0xA4, 0xA2, 0xC0, 0x2F, 0x25, 0x81, 0x22, 0xAF
} ;
Mike.
erskyTx/er9x developer
The difficult we do immediately,
The impossible takes a little longer!
The difficult we do immediately,
The impossible takes a little longer!
Re: LCD for 9XR board
Don't work... Nothing changed... My new lcd.cpp here below.
- MikeB
- 9x Developer
- Posts: 18000
- Joined: Tue Dec 27, 2011 1:24 pm
- Country: -
- Location: Poole, Dorset, UK
Re: LCD for 9XR board
In void refreshDiplay()
try changing:
lcdSendCtl( y | 0xB0); //page addr y
to
lcdSendCtl( (y ^ 0x04) | 0xB0); //page addr y
This should fix the display, buit the code will be specific to that display.
Mike.
try changing:
lcdSendCtl( y | 0xB0); //page addr y
to
lcdSendCtl( (y ^ 0x04) | 0xB0); //page addr y
This should fix the display, buit the code will be specific to that display.
Mike.
erskyTx/er9x developer
The difficult we do immediately,
The impossible takes a little longer!
The difficult we do immediately,
The impossible takes a little longer!
Re: LCD for 9XR board
Hi Mike, nothing helps... I tried to replace only y to (y ^ 0x04), compilling and flash it and make all of changes proposed by You. Situation has not changed. Small display continues to work with any lcd.cpp file changes.
Re: LCD for 9XR board
I feel so lonely...
- MikeB
- 9x Developer
- Posts: 18000
- Joined: Tue Dec 27, 2011 1:24 pm
- Country: -
- Location: Poole, Dorset, UK
Re: LCD for 9XR board
Sorry, I'll try to look at this today, I've been rather busy. The change I suggsted should have worked, and messed up other displays.
Mike.
Mike.
erskyTx/er9x developer
The difficult we do immediately,
The impossible takes a little longer!
The difficult we do immediately,
The impossible takes a little longer!
- MikeB
- 9x Developer
- Posts: 18000
- Joined: Tue Dec 27, 2011 1:24 pm
- Country: -
- Location: Poole, Dorset, UK
Re: LCD for 9XR board
The code has got THREE copies of refreshDiplay() in it, for different displays now.
You need to add the ^4 to THIS one:
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0x04);
lcdSendCtl(0x10); //column addr 0
lcdSendCtl( (y^4) | 0xB0); //page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
Mike.
You need to add the ^4 to THIS one:
for(uint8_t y=0; y < 8; y++) {
lcdSendCtl(0x04);
lcdSendCtl(0x10); //column addr 0
lcdSendCtl( (y^4) | 0xB0); //page addr y
PORTC_LCD_CTRL &= ~(1<<OUT_C_LCD_CS1);
Mike.
erskyTx/er9x developer
The difficult we do immediately,
The impossible takes a little longer!
The difficult we do immediately,
The impossible takes a little longer!