]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/STLcd/lcd_scan.c
Adding cli API call to set LCD backlight brightness (16 bit per channel)
[kiibohd-controller.git] / Scan / STLcd / lcd_scan.c
1 /* Copyright (C) 2015 by Jacob Alexander
2  *
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.
7  *
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.
12  *
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/>.
15  */
16
17 // ----- Includes -----
18
19 // Compiler Includes
20 #include <Lib/ScanLib.h>
21
22 // Project Includes
23 #include <cli.h>
24 #include <kll.h>
25 #include <led.h>
26 #include <print.h>
27
28 // Local Includes
29 #include "lcd_scan.h"
30
31
32
33 // ----- Defines -----
34
35 #define LCD_TOTAL_VISIBLE_PAGES 4
36 #define LCD_PAGE_LEN 128
37
38
39
40 // ----- Macros -----
41
42 // Number of entries in the SPI0 TxFIFO
43 #define SPI0_TxFIFO_CNT ( ( SPI0_SR & SPI_SR_TXCTR ) >> 12 )
44
45
46
47 // ----- Structs -----
48
49 // ----- Function Declarations -----
50
51 // CLI Functions
52 void cliFunc_lcdCmd  ( char* args );
53 void cliFunc_lcdColor( char* args );
54 void cliFunc_lcdInit ( char* args );
55 void cliFunc_lcdTest ( char* args );
56
57
58
59 // ----- Variables -----
60
61 // Full Toggle State
62 uint8_t cliFullToggleState = 0;
63
64 // Normal/Reverse Toggle State
65 uint8_t cliNormalReverseToggleState = 0;
66
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." );
72
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
79 };
80
81
82
83 // ----- Interrupt Functions -----
84
85
86
87 // ----- Functions -----
88
89 inline void SPI_setup()
90 {
91         // Enable SPI internal clock
92         SIM_SCGC6 |= SIM_SCGC6_SPI0;
93
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);
97
98         // Setup SS (PCS)
99         PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(2);
100
101         // Master Mode, CS0
102         SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(1);
103
104         // DSPI Clock and Transfer Attributes
105         // Frame Size: 8 bits
106         // MSB First
107         // CLK Low by default
108         SPI0_CTAR0 = SPI_CTAR_FMSZ(7)
109                 | SPI_CTAR_ASC(7)
110                 | SPI_CTAR_DT(7)
111                 | SPI_CTAR_CSSCK(7)
112                 | SPI_CTAR_PBR(0) | SPI_CTAR_BR(7);
113 }
114
115 // Write buffer to SPI FIFO
116 void SPI_write( uint8_t *buffer, uint8_t len )
117 {
118
119         for ( uint8_t byte = 0; byte < len; byte++ )
120         {
121                 // Wait for SPI TxFIFO to have 4 or fewer entries
122                 while ( !( SPI0_SR & SPI_SR_TFFF ) )
123                         delayMicroseconds(10);
124
125                 // Write byte to TxFIFO
126                 // CS0, CTAR0
127                 SPI0_PUSHR = ( buffer[ byte ] & 0xff ) | SPI_PUSHR_PCS(1);
128
129                 // Indicate transfer has completed
130                 while ( !( SPI0_SR & SPI_SR_TCF ) );
131                 SPI0_SR |= SPI_SR_TCF;
132         }
133 }
134
135 // Write to a control register
136 void LCD_writeControlReg( uint8_t byte )
137 {
138         // Wait for TxFIFO to be empt
139         while ( SPI0_TxFIFO_CNT != 0 );
140
141         // Set A0 low to enter control register mode
142         GPIOC_PCOR |= (1<<7);
143
144         // Write byte to SPI FIFO
145         SPI_write( &byte, 1 );
146
147         // Wait for TxFIFO to be empty
148         while ( SPI0_TxFIFO_CNT != 0 );
149
150         // Make sure data has transferred
151         delayMicroseconds(10); // XXX Adjust if SPI speed changes
152
153         // Set A0 high to go back to display register mode
154         GPIOC_PSOR |= (1<<7);
155 }
156
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 )
161 {
162         // Set the register page
163         LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
164
165         // Set display start line
166         LCD_writeControlReg( 0x40 );
167
168         // Reset Column Address
169         LCD_writeControlReg( 0x10 );
170         LCD_writeControlReg( 0x00 );
171
172         // Write buffer to SPI
173         SPI_write( buffer, len );
174 }
175
176 inline void LCD_clearPage( uint8_t page )
177 {
178         // Set the register page
179         LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
180
181         // Set display start line
182         LCD_writeControlReg( 0x40 );
183
184         // Reset Column Address
185         LCD_writeControlReg( 0x10 );
186         LCD_writeControlReg( 0x00 );
187
188         for ( uint8_t page_reg = 0; page_reg < LCD_PAGE_LEN; page_reg++ )
189         {
190                 uint8_t byte = 0;
191
192                 // Write buffer to SPI
193                 SPI_write( &byte, 1 );
194         }
195
196         // Wait for TxFIFO to be empty
197         while ( SPI0_TxFIFO_CNT != 0 );
198 }
199
200 // Clear Display
201 void LCD_clear()
202 {
203         // Setup each page
204         for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
205         {
206                 LCD_clearPage( page );
207         }
208
209         // Reset Page, Start Line, and Column Address
210         // Page
211         LCD_writeControlReg( 0xB0 );
212
213         // Start Line
214         LCD_writeControlReg( 0x40 );
215
216         // Reset Column Address
217         LCD_writeControlReg( 0x10 );
218         LCD_writeControlReg( 0x00 );
219 }
220
221 // Intialize display
222 void LCD_initialize()
223 {
224         // ADC Select (Normal)
225         LCD_writeControlReg( 0xA0 );
226
227         // LCD Off
228         LCD_writeControlReg( 0xAE );
229
230         // COM Scan Output Direction
231         LCD_writeControlReg( 0xC0 );
232
233         // LCD Bias (1/6 bias)
234         LCD_writeControlReg( 0xA2 );
235
236         // Power Supply Operating Mode (Internal Only)
237         LCD_writeControlReg( 0x2F );
238
239         // Internal Rb/Ra Ratio
240         LCD_writeControlReg( 0x26 );
241
242         // Reset
243         LCD_writeControlReg( 0xE2 );
244
245         // Electric volume mode set, and value
246         LCD_writeControlReg( 0x81 );
247         LCD_writeControlReg( 0x00 );
248
249         // LCD On
250         LCD_writeControlReg( 0xAF );
251
252         // Clear Display RAM
253         LCD_clear();
254 }
255
256 // Setup
257 inline void LCD_setup()
258 {
259         // Register Scan CLI dictionary
260         CLI_registerDictionary( lcdCLIDict, lcdCLIDictName );
261
262         // Initialize SPI
263         SPI_setup();
264
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);
270
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);
277
278         // Run LCD intialization sequence
279         LCD_initialize();
280
281         // Setup Backlight
282         // TODO Expose default settings
283         SIM_SCGC6 |= SIM_SCGC6_FTM0;
284         FTM0_CNT = 0; // Reset counter
285
286         // PWM Period
287         // 16-bit maximum
288         FTM0_MOD = 0xFFFF;
289
290         // Set FTM to PWM output - Edge Aligned, Low-true pulses
291         FTM0_C0SC = 0x24; // MSnB:MSnA = 10, ELSnB:ELSnA = 01
292         FTM0_C1SC = 0x24;
293         FTM0_C2SC = 0x24;
294
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
309
310         // System clock, /w prescalar setting
311         FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS( STLcdBacklightPrescalar_define );
312
313         // Red
314         FTM0_C0V = STLcdBacklightRed_define;
315         PORTC_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
316
317         // Green
318         FTM0_C1V = STLcdBacklightGreen_define;
319         PORTC_PCR2 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
320
321         // Blue
322         FTM0_C2V = STLcdBacklightBlue_define;
323         PORTC_PCR3 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
324 }
325
326
327 // LCD State processing loop
328 inline uint8_t LCD_scan()
329 {
330         // NOP - Screen Refresh
331         //LCD_writeControlReg( 0xE3 );
332         return 0;
333 }
334
335
336
337 // ----- CLI Command Functions -----
338
339 void cliFunc_lcdInit( char* args )
340 {
341         print( NL ); // No \r\n by default after the command is entered
342         LCD_initialize();
343 }
344
345 void cliFunc_lcdTest( char* args )
346 {
347         print( NL ); // No \r\n by default after the command is entered
348
349         //LCD_initialize();
350         // Test pattern
351         uint8_t pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
352
353
354 uint8_t logo[] = {
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,
359 };
360         //uint8_t pattern[] = { 0xFF, 0x00, 0x96, 0xFF, 0x00, 0xFF, 0x00 };
361
362         // Write to page D0
363         //LCD_writeDisplayReg( 0, pattern, sizeof( pattern ) );
364
365         for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
366         {
367                 LCD_writeDisplayReg( page, &logo[page * LCD_PAGE_LEN], LCD_PAGE_LEN );
368         }
369 }
370
371 void cliFunc_lcdCmd( char* args )
372 {
373         char* curArgs;
374         char* arg1Ptr;
375         char* arg2Ptr = args;
376
377         print( NL ); // No \r\n by default after the command is entered
378
379         curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
380         CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
381
382         // No args
383         if ( *arg1Ptr == '\0' )
384                 return;
385
386         // SPI Command
387         uint8_t cmd = (uint8_t)numToInt( arg1Ptr );
388
389         curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
390         CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
391
392         // Single Arg
393         if ( *arg1Ptr == '\0' )
394                 goto cmd;
395
396         // TODO Deal with a0
397 cmd:
398         info_msg("Sending - ");
399         printHex( cmd );
400         print( NL );
401         LCD_writeControlReg( cmd );
402 }
403
404 void cliFunc_lcdColor( char* args )
405 {
406         char* curArgs;
407         char* arg1Ptr;
408         char* arg2Ptr = args;
409
410         // Colors
411         uint16_t rgb[3]; // Red, Green, Blue
412
413         // Parse integers from 3 arguments
414         for ( uint8_t color = 0; color < 3; color++ )
415         {
416                 curArgs = arg2Ptr;
417                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
418
419                 // Give up if not enough args given
420                 if ( *arg1Ptr == '\0' )
421                         return;
422
423                 // Convert argument to integer
424                 rgb[ color ] = numToInt( arg1Ptr );
425         }
426
427         // Set PWM channels
428         FTM0_C0V = rgb[0];
429         FTM0_C1V = rgb[1];
430         FTM0_C2V = rgb[2];
431
432         print( NL ); // No \r\n by default after the command is entered
433 }
434