266 lines
5.8 KiB
C
266 lines
5.8 KiB
C
#include "ch.h"
|
|
#include "hal.h"
|
|
|
|
#include "ssd1963.h"
|
|
|
|
|
|
#define _command 0x40
|
|
#define _delay 0x80
|
|
#define _ndata(x) ( (u8)( (x) & 0x3f) )
|
|
|
|
static const u8 _ssd1963_reset_sequence[ ] = {
|
|
/*
|
|
* PLL configuration
|
|
* -----------------
|
|
*
|
|
* PLL = input * ( P1 + 1 ) / ( P2 + 1 )
|
|
* (P1 : 8 bits ; P2 : 4 bits; P3 : junk)
|
|
*
|
|
* 1/ The ITDB02-4.3 board has a 12MHz crystal (which contradicts the
|
|
* SSD1963 datasheet - wtf?).
|
|
* 2/ The SSD1963 must be clocked at *at most* 110MHz.
|
|
* 3/ Also, 250MHz < input * ( P1 + 1 ) < 800MHz
|
|
* 4/ The STM32F4 can communicate at 50MHz.
|
|
* 5/ The SSD1963 accepts PLL/2 accesses per second.
|
|
*
|
|
* 100MHz = 12MHz * ( P1 + 1 ) / ( P2 + 1 )
|
|
* => P1 = 49, P2 = 5
|
|
* 100MHz = 10MHz * ( P1 + 1 ) / ( P2 + 1 )
|
|
* => P1 = 19, P2 = 1
|
|
*/
|
|
_command | _ndata(3) ,
|
|
SSD1963_CMD_SET_PLL_MN ,
|
|
0x31 , 0x05 , 0x04 ,
|
|
// 0x1e , 0x02 , 0x04 ,
|
|
|
|
// Enable PLL and wait until it's stable
|
|
_command | _delay | _ndata(1) ,
|
|
SSD1963_CMD_SET_PLL , 1 ,
|
|
1 ,
|
|
|
|
// Fully enable PLL
|
|
_command | _ndata(1) ,
|
|
SSD1963_CMD_SET_PLL , 3 ,
|
|
};
|
|
|
|
|
|
static const u8 _ssd1963_init_sequence[ ] = {
|
|
// Software reset
|
|
_command | _delay ,
|
|
SSD1963_CMD_SOFT_RESET ,
|
|
5 ,
|
|
|
|
/* Pixel clock: screw finesse, crank that up to the max */
|
|
_command | _ndata( 3 ) | _delay ,
|
|
SSD1963_CMD_SET_LSHIFT_FREQ ,
|
|
0x07 , 0xff , 0xff ,
|
|
15 ,
|
|
|
|
// Use 565 RGB format
|
|
_command | _delay | _ndata(1) ,
|
|
SSD1963_CMD_SET_PIXEL_FORMAT ,
|
|
0x03 ,
|
|
5 ,
|
|
|
|
// Setup LCD panel
|
|
_command | _ndata( 7 ) ,
|
|
SSD1963_CMD_SET_LCD_MODE ,
|
|
0x20 , // Data width 24-bit, FRC and dithering disabled
|
|
// Data latch on falling edge
|
|
// HSync polarity: active low
|
|
// VSync polarity: active low
|
|
0x00 , // TFT mode
|
|
// Width
|
|
( ( ( SSD1963_SCR_WIDTH - 1 ) >> 8 ) & 0xff ) ,
|
|
( ( SSD1963_SCR_WIDTH - 1 ) & 0xff ) ,
|
|
// Height
|
|
( ( ( SSD1963_SCR_HEIGHT - 1 ) >> 8 ) & 0xff ) ,
|
|
( ( SSD1963_SCR_HEIGHT - 1 ) & 0xff ) ,
|
|
0x00 , // Ignored (serial interface)
|
|
|
|
_command | _ndata( 8 ) ,
|
|
SSD1963_CMD_SET_HORI_PERIOD ,
|
|
0x02 , 0x13 , // Total period (PCLK)
|
|
0x00 , 0x08 , // Non-display period
|
|
0x2b , // Sync pulse width (PCLK)
|
|
0x00 , 0x02 , // Start location (PCLK)
|
|
0x00 , // Ignored (serial interfaces)
|
|
|
|
_command | _ndata( 7 ) ,
|
|
SSD1963_CMD_SET_VERT_PERIOD ,
|
|
0x01 , 0x20 , // Vertical total period
|
|
0x00 , 0x04 , // Non-display period
|
|
0x0c , // Sync pulse width
|
|
0x00 , 0x02 , // Start location
|
|
|
|
_command | _ndata(1) ,
|
|
0x36 ,
|
|
0x00 ,
|
|
|
|
_command ,
|
|
SSD1963_CMD_SET_DISPLAY_ON ,
|
|
|
|
_command | _ndata(6) ,
|
|
SSD1963_CMD_SET_PWM_CONF ,
|
|
0x06 , 0xf0 , 0x01 , 0xf0 , 0 , 0 ,
|
|
|
|
_command | _ndata(1) ,
|
|
0xd0 ,
|
|
0x0d ,
|
|
|
|
_command | _ndata(1) , SSD1963_CMD_SET_GAMMA_CURVE, 1 ,
|
|
//_command | SSD1963_CMD_ENTER_NORMAL_MODE ,
|
|
//_command | SSD1963_CMD_EXIT_INVERT_MODE ,
|
|
_command , SSD1963_CMD_EXIT_IDLE_MODE ,
|
|
/*
|
|
SSD1963_CMD_SET_TEAR_OFF ,
|
|
*/
|
|
};
|
|
|
|
|
|
#define _ssd1963_wcmd(command) \
|
|
do { \
|
|
_ssd1963_clear_rs; \
|
|
_ssd1963_write( command ); \
|
|
_ssd1963_clear_wr; \
|
|
_ssd1963_set_wr; \
|
|
} while ( FALSE )
|
|
#define _ssd1963_wdata(data) \
|
|
do { \
|
|
_ssd1963_set_rs; \
|
|
_ssd1963_write( data ); \
|
|
_ssd1963_clear_wr; \
|
|
_ssd1963_set_wr; \
|
|
} while ( FALSE )
|
|
|
|
|
|
void _ssd1963_run_sequence( const u8 * sequence , u32 size )
|
|
{
|
|
_ssd1963_clear_cs;
|
|
|
|
u32 addr = 0;
|
|
u8 has_command = 0 , has_data = 0 , has_delay = 0;
|
|
while ( addr < size ) {
|
|
if ( has_command ) {
|
|
u16 command = sequence[ addr ++ ];
|
|
_ssd1963_wcmd( command );
|
|
has_command = 0;
|
|
} else if ( has_data ) {
|
|
u16 data = sequence[ addr ++ ];
|
|
_ssd1963_wdata( data );
|
|
has_data --;
|
|
} else if ( has_delay ) {
|
|
u8 delay = sequence[ addr ++ ];
|
|
chThdSleep( delay );
|
|
has_delay = 0;
|
|
} else {
|
|
u8 value = sequence[ addr ++ ];
|
|
has_command = ( ( value & _command ) == _command );
|
|
has_delay = ( ( value & _delay ) == _delay );
|
|
has_data = value & ~( _command | _delay );
|
|
}
|
|
}
|
|
|
|
_ssd1963_set_cs;
|
|
}
|
|
|
|
|
|
void _ssd1963_reset_chip( void )
|
|
{
|
|
// Select and reset the chip
|
|
_ssd1963_set_reset;
|
|
_ssd1963_set_cs;
|
|
_ssd1963_set_rd;
|
|
_ssd1963_set_wr;
|
|
_ssd1963_clear_reset;
|
|
chThdSleep( 100 );
|
|
_ssd1963_set_reset;
|
|
chThdSleep( 100 );
|
|
|
|
// Run the PLL init sequence
|
|
_ssd1963_run_sequence( _ssd1963_reset_sequence ,
|
|
sizeof( _ssd1963_reset_sequence ) );
|
|
}
|
|
|
|
|
|
|
|
void _ssd1963_set_pos( u32 x , u32 y )
|
|
{
|
|
_ssd1963_wcmd( 0x2a );
|
|
_ssd1963_wdata( x >> 8 );
|
|
_ssd1963_wdata( x & 0xff );
|
|
_ssd1963_wdata( ( ( SSD1963_SCR_WIDTH - 1 ) >> 8 ) & 0xff );
|
|
_ssd1963_wdata( ( SSD1963_SCR_WIDTH - 1 ) & 0xff );
|
|
_ssd1963_wcmd( 0x2b );
|
|
_ssd1963_wdata( y >> 8 );
|
|
_ssd1963_wdata( y & 0xff );
|
|
_ssd1963_wdata( ( ( SSD1963_SCR_HEIGHT - 1 ) >> 8 ) & 0xff );
|
|
_ssd1963_wdata( ( SSD1963_SCR_HEIGHT - 1 ) & 0xff );
|
|
_ssd1963_wcmd( 0x2c );
|
|
}
|
|
|
|
|
|
|
|
void ssd1963Init( void )
|
|
{
|
|
_ssd1963_init_gpio( PAL_STM32_OSPEED_LOWEST );
|
|
chThdSleep( 10 );
|
|
_ssd1963_reset_chip( );
|
|
|
|
chThdSleep( 10 );
|
|
_ssd1963_init_gpio( PAL_STM32_OSPEED_HIGHEST );
|
|
_ssd1963_run_sequence( _ssd1963_init_sequence ,
|
|
sizeof( _ssd1963_init_sequence ) );
|
|
|
|
_ssd1963_clear_cs;
|
|
_ssd1963_set_pos( 0 , 0 );
|
|
int i;
|
|
for ( i = 0 ; i < SSD1963_SCR_HEIGHT ; i ++ ) {
|
|
u16 j , c = 0x8000;
|
|
for ( j = 0 ; j < SSD1963_SCR_WIDTH ; j ++ ) {
|
|
if ( ( j & 7 ) == 7 ) {
|
|
c >>= 1;
|
|
if ( !c ) {
|
|
c = 0x8000;
|
|
}
|
|
}
|
|
_ssd1963_wdata( c );
|
|
}
|
|
}
|
|
_ssd1963_set_cs;
|
|
}
|
|
|
|
|
|
void display_test_pattern( u16 start_mask )
|
|
{
|
|
_ssd1963_clear_cs;
|
|
_ssd1963_set_pos( 0 , 0 );
|
|
int i;
|
|
for ( i = 0 ; i < SSD1963_SCR_HEIGHT ; i ++ ) {
|
|
u16 j , c = start_mask;
|
|
for ( j = 0 ; j < SSD1963_SCR_WIDTH ; j ++ ) {
|
|
if ( ( j & 7 ) == 7 ) {
|
|
c >>= 1;
|
|
if ( !c ) {
|
|
c = 0x8000;
|
|
}
|
|
}
|
|
_ssd1963_wdata( c );
|
|
}
|
|
}
|
|
_ssd1963_set_cs;
|
|
}
|
|
|
|
|
|
void display_off( void )
|
|
{
|
|
static int display = 1;
|
|
display = !display;
|
|
_ssd1963_clear_cs;
|
|
if ( display ) {
|
|
_ssd1963_wcmd( SSD1963_CMD_SET_DISPLAY_ON );
|
|
} else {
|
|
_ssd1963_wcmd( SSD1963_CMD_SET_DISPLAY_OFF );
|
|
}
|
|
_ssd1963_set_cs;
|
|
}
|