1 /* Copyright (C) 2015 by Jacob Alexander
3 * This file is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This file is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this file. If not, see <http://www.gnu.org/licenses/>.
17 // ----- Includes -----
20 #include <Lib/ScanLib.h>
33 // ----- Defines -----
35 #define LCD_TOTAL_VISIBLE_PAGES 4
36 #define LCD_PAGE_LEN 128
42 // Number of entries in the SPI0 TxFIFO
43 #define SPI0_TxFIFO_CNT ( ( SPI0_SR & SPI_SR_TXCTR ) >> 12 )
47 // ----- Structs -----
49 // ----- Function Declarations -----
52 void cliFunc_lcdCmd ( char* args );
53 void cliFunc_lcdColor( char* args );
54 void cliFunc_lcdInit ( char* args );
55 void cliFunc_lcdTest ( char* args );
59 // ----- Variables -----
62 uint8_t cliFullToggleState = 0;
64 // Normal/Reverse Toggle State
65 uint8_t cliNormalReverseToggleState = 0;
67 // Scan Module command dictionary
68 CLIDict_Entry( lcdCmd, "Send byte via SPI, second argument enables a0. Defaults to control." );
69 CLIDict_Entry( lcdColor, "Set backlight color. 3 16-bit numbers: R G B. i.e. 0xFFF 0x1444 0x32" );
70 CLIDict_Entry( lcdInit, "Re-initialize the LCD display." );
71 CLIDict_Entry( lcdTest, "Test out the LCD display." );
73 CLIDict_Def( lcdCLIDict, "ST LCD Module Commands" ) = {
74 CLIDict_Item( lcdCmd ),
75 CLIDict_Item( lcdColor ),
76 CLIDict_Item( lcdInit ),
77 CLIDict_Item( lcdTest ),
78 { 0, 0, 0 } // Null entry for dictionary end
83 // ----- Interrupt Functions -----
87 // ----- Functions -----
89 inline void SPI_setup()
91 // Enable SPI internal clock
92 SIM_SCGC6 |= SIM_SCGC6_SPI0;
94 // Setup MOSI (SOUT) and SCLK (SCK)
95 PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
96 PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(2);
99 PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(2);
102 SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(1);
104 // DSPI Clock and Transfer Attributes
105 // Frame Size: 8 bits
107 // CLK Low by default
108 SPI0_CTAR0 = SPI_CTAR_FMSZ(7)
112 | SPI_CTAR_PBR(0) | SPI_CTAR_BR(7);
115 // Write buffer to SPI FIFO
116 void SPI_write( uint8_t *buffer, uint8_t len )
119 for ( uint8_t byte = 0; byte < len; byte++ )
121 // Wait for SPI TxFIFO to have 4 or fewer entries
122 while ( !( SPI0_SR & SPI_SR_TFFF ) )
123 delayMicroseconds(10);
125 // Write byte to TxFIFO
127 SPI0_PUSHR = ( buffer[ byte ] & 0xff ) | SPI_PUSHR_PCS(1);
129 // Indicate transfer has completed
130 while ( !( SPI0_SR & SPI_SR_TCF ) );
131 SPI0_SR |= SPI_SR_TCF;
135 // Write to a control register
136 void LCD_writeControlReg( uint8_t byte )
138 // Wait for TxFIFO to be empt
139 while ( SPI0_TxFIFO_CNT != 0 );
141 // Set A0 low to enter control register mode
142 GPIOC_PCOR |= (1<<7);
144 // Write byte to SPI FIFO
145 SPI_write( &byte, 1 );
147 // Wait for TxFIFO to be empty
148 while ( SPI0_TxFIFO_CNT != 0 );
150 // Make sure data has transferred
151 delayMicroseconds(10); // XXX Adjust if SPI speed changes
153 // Set A0 high to go back to display register mode
154 GPIOC_PSOR |= (1<<7);
157 // Write to display register
158 // Pages 0-7 normal display
159 // Page 8 icon buffer
160 void LCD_writeDisplayReg( uint8_t page, uint8_t *buffer, uint8_t len )
162 // Set the register page
163 LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
165 // Set display start line
166 LCD_writeControlReg( 0x40 );
168 // Reset Column Address
169 LCD_writeControlReg( 0x10 );
170 LCD_writeControlReg( 0x00 );
172 // Write buffer to SPI
173 SPI_write( buffer, len );
176 inline void LCD_clearPage( uint8_t page )
178 // Set the register page
179 LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
181 // Set display start line
182 LCD_writeControlReg( 0x40 );
184 // Reset Column Address
185 LCD_writeControlReg( 0x10 );
186 LCD_writeControlReg( 0x00 );
188 for ( uint8_t page_reg = 0; page_reg < LCD_PAGE_LEN; page_reg++ )
192 // Write buffer to SPI
193 SPI_write( &byte, 1 );
196 // Wait for TxFIFO to be empty
197 while ( SPI0_TxFIFO_CNT != 0 );
204 for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
206 LCD_clearPage( page );
209 // Reset Page, Start Line, and Column Address
211 LCD_writeControlReg( 0xB0 );
214 LCD_writeControlReg( 0x40 );
216 // Reset Column Address
217 LCD_writeControlReg( 0x10 );
218 LCD_writeControlReg( 0x00 );
222 void LCD_initialize()
224 // ADC Select (Normal)
225 LCD_writeControlReg( 0xA0 );
228 LCD_writeControlReg( 0xAE );
230 // COM Scan Output Direction
231 LCD_writeControlReg( 0xC0 );
233 // LCD Bias (1/6 bias)
234 LCD_writeControlReg( 0xA2 );
236 // Power Supply Operating Mode (Internal Only)
237 LCD_writeControlReg( 0x2F );
239 // Internal Rb/Ra Ratio
240 LCD_writeControlReg( 0x26 );
243 LCD_writeControlReg( 0xE2 );
245 // Electric volume mode set, and value
246 LCD_writeControlReg( 0x81 );
247 LCD_writeControlReg( 0x00 );
250 LCD_writeControlReg( 0xAF );
257 inline void LCD_setup()
259 // Register Scan CLI dictionary
260 CLI_registerDictionary( lcdCLIDict, lcdCLIDictName );
265 // Setup Register Control Signal (A0)
266 // Start in display register mode (1)
267 GPIOC_PDDR |= (1<<7);
268 PORTC_PCR7 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
269 GPIOC_PSOR |= (1<<7);
271 // Setup LCD Reset pin (RST)
272 // 0 - Reset, 1 - Normal Operation
273 // Start in normal mode (1)
274 GPIOC_PDDR |= (1<<8);
275 PORTC_PCR8 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
276 GPIOC_PSOR |= (1<<8);
278 // Run LCD intialization sequence
282 // TODO Expose default settings
283 SIM_SCGC6 |= SIM_SCGC6_FTM0;
284 FTM0_CNT = 0; // Reset counter
290 // Set FTM to PWM output - Edge Aligned, Low-true pulses
291 FTM0_C0SC = 0x24; // MSnB:MSnA = 10, ELSnB:ELSnA = 01
295 // Base FTM clock selection (72 MHz system clock)
296 // @ 0xFFFF period, 72 MHz / 0xFFFF * 2 = Actual period
297 // Higher pre-scalar will use the most power (also look the best)
298 // Pre-scalar calculations
299 // 0 - 72 MHz -> 549 Hz
300 // 1 - 36 MHz -> 275 Hz
301 // 2 - 18 MHz -> 137 Hz
302 // 3 - 9 MHz -> 69 Hz (Slightly visible flicker)
303 // 4 - 4 500 kHz -> 34 Hz (Visible flickering)
304 // 5 - 2 250 kHz -> 17 Hz
305 // 6 - 1 125 kHz -> 9 Hz
306 // 7 - 562 500 Hz -> 4 Hz
307 // Using a higher pre-scalar without flicker is possible but FTM0_MOD will need to be reduced
308 // Which will reduce the brightness range
310 // System clock, /w prescalar setting
311 FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS( STLcdBacklightPrescalar_define );
314 FTM0_C0V = STLcdBacklightRed_define;
315 PORTC_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
318 FTM0_C1V = STLcdBacklightGreen_define;
319 PORTC_PCR2 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
322 FTM0_C2V = STLcdBacklightBlue_define;
323 PORTC_PCR3 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
327 // LCD State processing loop
328 inline uint8_t LCD_scan()
330 // NOP - Screen Refresh
331 //LCD_writeControlReg( 0xE3 );
337 // ----- CLI Command Functions -----
339 void cliFunc_lcdInit( char* args )
341 print( NL ); // No \r\n by default after the command is entered
345 void cliFunc_lcdTest( char* args )
347 print( NL ); // No \r\n by default after the command is entered
351 uint8_t pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
355 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
356 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
357 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
358 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
360 //uint8_t pattern[] = { 0xFF, 0x00, 0x96, 0xFF, 0x00, 0xFF, 0x00 };
363 //LCD_writeDisplayReg( 0, pattern, sizeof( pattern ) );
365 for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
367 LCD_writeDisplayReg( page, &logo[page * LCD_PAGE_LEN], LCD_PAGE_LEN );
371 void cliFunc_lcdCmd( char* args )
375 char* arg2Ptr = args;
377 print( NL ); // No \r\n by default after the command is entered
379 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
380 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
383 if ( *arg1Ptr == '\0' )
387 uint8_t cmd = (uint8_t)numToInt( arg1Ptr );
389 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
390 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
393 if ( *arg1Ptr == '\0' )
398 info_msg("Sending - ");
401 LCD_writeControlReg( cmd );
404 void cliFunc_lcdColor( char* args )
408 char* arg2Ptr = args;
411 uint16_t rgb[3]; // Red, Green, Blue
413 // Parse integers from 3 arguments
414 for ( uint8_t color = 0; color < 3; color++ )
417 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
419 // Give up if not enough args given
420 if ( *arg1Ptr == '\0' )
423 // Convert argument to integer
424 rgb[ color ] = numToInt( arg1Ptr );
432 print( NL ); // No \r\n by default after the command is entered