]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/STLcd/lcd_scan.c
Adding 16-bit brightness control to LCD backlight
[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_lcdInit( char* args );
54 void cliFunc_lcdTest( char* args );
55
56
57
58 // ----- Variables -----
59
60 // Full Toggle State
61 uint8_t cliFullToggleState = 0;
62
63 // Normal/Reverse Toggle State
64 uint8_t cliNormalReverseToggleState = 0;
65
66 // Scan Module command dictionary
67 CLIDict_Entry( lcdCmd,      "Send byte via SPI, second argument enables a0. Defaults to control." );
68 CLIDict_Entry( lcdInit,     "Re-initialize the LCD display." );
69 CLIDict_Entry( lcdTest,     "Test out the LCD display." );
70
71 CLIDict_Def( lcdCLIDict, "ST LCD Module Commands" ) = {
72         CLIDict_Item( lcdCmd ),
73         CLIDict_Item( lcdInit ),
74         CLIDict_Item( lcdTest ),
75         { 0, 0, 0 } // Null entry for dictionary end
76 };
77
78
79
80 // ----- Interrupt Functions -----
81
82
83
84 // ----- Functions -----
85
86 inline void SPI_setup()
87 {
88         // Enable SPI internal clock
89         SIM_SCGC6 |= SIM_SCGC6_SPI0;
90
91         // Setup MOSI (SOUT) and SCLK (SCK)
92         PORTC_PCR6 = PORT_PCR_DSE | PORT_PCR_MUX(2);
93         PORTC_PCR5 = PORT_PCR_DSE | PORT_PCR_MUX(2);
94
95         // Setup SS (PCS)
96         PORTC_PCR4 = PORT_PCR_DSE | PORT_PCR_MUX(2);
97
98         // Master Mode, CS0
99         SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(1);
100
101         // DSPI Clock and Transfer Attributes
102         // Frame Size: 8 bits
103         // MSB First
104         // CLK Low by default
105         SPI0_CTAR0 = SPI_CTAR_FMSZ(7)
106                 | SPI_CTAR_ASC(7)
107                 | SPI_CTAR_DT(7)
108                 | SPI_CTAR_CSSCK(7)
109                 | SPI_CTAR_PBR(0) | SPI_CTAR_BR(7);
110 }
111
112 // Write buffer to SPI FIFO
113 void SPI_write( uint8_t *buffer, uint8_t len )
114 {
115
116         for ( uint8_t byte = 0; byte < len; byte++ )
117         {
118                 // Wait for SPI TxFIFO to have 4 or fewer entries
119                 while ( !( SPI0_SR & SPI_SR_TFFF ) )
120                         delayMicroseconds(10);
121
122                 // Write byte to TxFIFO
123                 // CS0, CTAR0
124                 SPI0_PUSHR = ( buffer[ byte ] & 0xff ) | SPI_PUSHR_PCS(1);
125
126                 // Indicate transfer has completed
127                 while ( !( SPI0_SR & SPI_SR_TCF ) );
128                 SPI0_SR |= SPI_SR_TCF;
129         }
130 }
131
132 // Write to a control register
133 void LCD_writeControlReg( uint8_t byte )
134 {
135         // Wait for TxFIFO to be empt
136         while ( SPI0_TxFIFO_CNT != 0 );
137
138         // Set A0 low to enter control register mode
139         GPIOC_PCOR |= (1<<7);
140
141         // Write byte to SPI FIFO
142         SPI_write( &byte, 1 );
143
144         // Wait for TxFIFO to be empty
145         while ( SPI0_TxFIFO_CNT != 0 );
146
147         // Make sure data has transferred
148         delayMicroseconds(10); // XXX Adjust if SPI speed changes
149
150         // Set A0 high to go back to display register mode
151         GPIOC_PSOR |= (1<<7);
152 }
153
154 // Write to display register
155 // Pages 0-7 normal display
156 // Page  8   icon buffer
157 void LCD_writeDisplayReg( uint8_t page, uint8_t *buffer, uint8_t len )
158 {
159         // Set the register page
160         LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
161
162         // Set display start line
163         LCD_writeControlReg( 0x40 );
164
165         // Reset Column Address
166         LCD_writeControlReg( 0x10 );
167         LCD_writeControlReg( 0x00 );
168
169         // Write buffer to SPI
170         SPI_write( buffer, len );
171 }
172
173 inline void LCD_clearPage( uint8_t page )
174 {
175         // Set the register page
176         LCD_writeControlReg( 0xB0 | ( 0x0F & page ) );
177
178         // Set display start line
179         LCD_writeControlReg( 0x40 );
180
181         // Reset Column Address
182         LCD_writeControlReg( 0x10 );
183         LCD_writeControlReg( 0x00 );
184
185         for ( uint8_t page_reg = 0; page_reg < LCD_PAGE_LEN; page_reg++ )
186         {
187                 uint8_t byte = 0;
188
189                 // Write buffer to SPI
190                 SPI_write( &byte, 1 );
191         }
192
193         // Wait for TxFIFO to be empty
194         while ( SPI0_TxFIFO_CNT != 0 );
195 }
196
197 // Clear Display
198 void LCD_clear()
199 {
200         // Setup each page
201         for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
202         {
203                 LCD_clearPage( page );
204         }
205
206         // Reset Page, Start Line, and Column Address
207         // Page
208         LCD_writeControlReg( 0xB0 );
209
210         // Start Line
211         LCD_writeControlReg( 0x40 );
212
213         // Reset Column Address
214         LCD_writeControlReg( 0x10 );
215         LCD_writeControlReg( 0x00 );
216 }
217
218 // Intialize display
219 void LCD_initialize()
220 {
221         // ADC Select (Normal)
222         LCD_writeControlReg( 0xA0 );
223
224         // LCD Off
225         LCD_writeControlReg( 0xAE );
226
227         // COM Scan Output Direction
228         LCD_writeControlReg( 0xC0 );
229
230         // LCD Bias (1/6 bias)
231         LCD_writeControlReg( 0xA2 );
232
233         // Power Supply Operating Mode (Internal Only)
234         LCD_writeControlReg( 0x2F );
235
236         // Internal Rb/Ra Ratio
237         LCD_writeControlReg( 0x26 );
238
239         // Reset
240         LCD_writeControlReg( 0xE2 );
241
242         // Electric volume mode set, and value
243         LCD_writeControlReg( 0x81 );
244         LCD_writeControlReg( 0x00 );
245
246         // LCD On
247         LCD_writeControlReg( 0xAF );
248
249         // Clear Display RAM
250         LCD_clear();
251 }
252
253 // Setup
254 inline void LCD_setup()
255 {
256         // Register Scan CLI dictionary
257         CLI_registerDictionary( lcdCLIDict, lcdCLIDictName );
258
259         // Initialize SPI
260         SPI_setup();
261
262         // Setup Register Control Signal (A0)
263         // Start in display register mode (1)
264         GPIOC_PDDR |= (1<<7);
265         PORTC_PCR7 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
266         GPIOC_PSOR |= (1<<7);
267
268         // Setup LCD Reset pin (RST)
269         // 0 - Reset, 1 - Normal Operation
270         // Start in normal mode (1)
271         GPIOC_PDDR |= (1<<8);
272         PORTC_PCR8 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
273         GPIOC_PSOR |= (1<<8);
274
275         // Run LCD intialization sequence
276         LCD_initialize();
277
278         // Setup Backlight
279         // TODO Expose default settings
280         SIM_SCGC6 |= SIM_SCGC6_FTM0;
281         FTM0_CNT = 0; // Reset counter
282
283         // PWM Period
284         // 16-bit maximum
285         FTM0_MOD = 0xFFFF;
286
287         // Set FTM to PWM output - Edge Aligned, Low-true pulses
288         FTM0_C0SC = 0x24; // MSnB:MSnA = 10, ELSnB:ELSnA = 01
289         FTM0_C1SC = 0x24;
290         FTM0_C2SC = 0x24;
291
292         // Base FTM clock selection (72 MHz system clock)
293         // Pre-scalar calculations
294         // 0 -      72 MHz - Highest power usage/best result
295         // 1 -      36 MHz
296         // 2 -      18 MHz
297         // 3 -       9 MHz - Slightly visible flicker (peripheral vision)
298         // 4 -   4 500 kHz - Visible flickering
299         // 5 -   2 250 kHz
300         // 6 -   1 125 kHz
301         // 7 - 562 500  Hz
302         // System clock, /w prescalar setting
303         FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS( STLcdBacklightPrescalar_define );
304
305         /* Write frequency TODO API
306         FTM0_SC = 0;
307         FTM0_CNT = 0;
308         FTM0_MOD = mod;
309         FTM0_SC = FTM_SC_CLKS(1) | FTM_SC_PS(prescale);
310         */
311
312         // Red
313         FTM0_C0V = STLcdBacklightRed_define;
314         PORTC_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
315
316         // Green
317         FTM0_C1V = STLcdBacklightGreen_define;
318         PORTC_PCR2 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
319
320         // Blue
321         FTM0_C2V = STLcdBacklightBlue_define;
322         PORTC_PCR3 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(4);
323 }
324
325
326 // LCD State processing loop
327 inline uint8_t LCD_scan()
328 {
329         // NOP - Screen Refresh
330         //LCD_writeControlReg( 0xE3 );
331         return 0;
332 }
333
334
335
336 // ----- CLI Command Functions -----
337
338 void cliFunc_lcdInit( char* args )
339 {
340         print( NL ); // No \r\n by default after the command is entered
341         LCD_initialize();
342 }
343
344 void cliFunc_lcdTest( char* args )
345 {
346         print( NL ); // No \r\n by default after the command is entered
347
348         //LCD_initialize();
349         // Test pattern
350         uint8_t pattern[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
351
352
353 uint8_t logo[] = {
354 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,
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, 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,
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, 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,
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, 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,
358 };
359         //uint8_t pattern[] = { 0xFF, 0x00, 0x96, 0xFF, 0x00, 0xFF, 0x00 };
360
361         // Write to page D0
362         //LCD_writeDisplayReg( 0, pattern, sizeof( pattern ) );
363
364         for ( uint8_t page = 0; page < LCD_TOTAL_VISIBLE_PAGES; page++ )
365         {
366                 LCD_writeDisplayReg( page, &logo[page * LCD_PAGE_LEN], LCD_PAGE_LEN );
367         }
368 }
369
370 void cliFunc_lcdCmd( char* args )
371 {
372         char* curArgs;
373         char* arg1Ptr;
374         char* arg2Ptr = args;
375
376         print( NL ); // No \r\n by default after the command is entered
377
378         curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
379         CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
380
381         // No args
382         if ( *arg1Ptr == '\0' )
383                 return;
384
385         // SPI Command
386         uint8_t cmd = (uint8_t)numToInt( arg1Ptr );
387
388         curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
389         CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
390
391         // Single Arg
392         if ( *arg1Ptr == '\0' )
393                 goto cmd;
394
395         // TODO Deal with a0
396 cmd:
397         info_msg("Sending - ");
398         printHex( cmd );
399         print( NL );
400         LCD_writeControlReg( cmd );
401 }
402