]> git.karo-electronics.de Git - oswald.git/blob - metawatch/mw_lcd.c
Shorten charger plug "tail"
[oswald.git] / metawatch / mw_lcd.c
1 #include <msp430.h>
2 #include <stdint.h>
3
4 #include "mw_main.h"
5
6 #include "mw_lcd.h"
7 #include "mw_uart.h"
8
9 // SMCLK = 16MHz -> divide by 16 to get 1 MHz SPI clock,
10 // 1MHz maximum according to LCD spec
11 //#define SPI_PRESCALE_L                0x10
12 // currently we only run @1MHz
13 #define SPI_PRESCALE_L          0x10
14 #define SPI_PRESCALE_H          0x00
15
16 #define LCD_STATIC_CMD          0x00
17 #define LCD_WRITE_CMD           0x01
18 #define LCD_CLEAR_CMD           0x04     
19
20 static const unsigned char LCD_CLEAR_COMMAND[] = {LCD_CLEAR_CMD, 0x00};
21 #define LCD_CLEAR_CMD_SIZE      0x02
22 static const unsigned char LCD_STATIC_COMMAND[] = {LCD_STATIC_CMD, 0x00};
23 #define LCD_STATIC_CMD_SIZE     0x02
24
25
26 /* the LCD frame buffer, 96 lines */
27 tLcdLine lcd_buf[96];
28
29
30 #define LCD_DMA
31 /* errata - DMA variables cannot be function scope */
32 #ifdef LCD_DMA
33 static unsigned char LcdDmaBusy = 0;
34 #endif
35
36
37 void memfill(void *target, unsigned char val, unsigned int count)
38 {
39         while (count--) {
40                 *(unsigned char *)(target+count) = val;
41         }
42 }
43
44 void mw_lcd_init(void)
45 {
46         int i;
47
48         /* basic I/O setup */
49         ENABLE_LCD_POWER();
50         CONFIG_LCD_PINS();
51
52         // DISABLE_LCD_ENABLE();
53         ENABLE_LCD_ENABLE();
54
55         /* Put state machine in reset while it is configured */
56         LCD_SPI_UCBxCTL1 |= UCSWRST;
57
58         /* 
59          * 3-pin, 8-bit SPI master, Clock polarity low
60          * Clock phase set, least sig bit first
61          * SMCLK is the clock source
62          * set the clock prescaler
63          */
64         LCD_SPI_UCBxCTL0 |= UCMST+ UCCKPH + UCSYNC;      
65
66         LCD_SPI_UCBxCTL1 |= UCSSEL_2;                    
67         LCD_SPI_UCBxBR0 = SPI_PRESCALE_L;               
68         LCD_SPI_UCBxBR1 = SPI_PRESCALE_H;               
69
70         /* remove reset */
71         LCD_SPI_UCBxCTL1 &= ~UCSWRST;
72
73         /* pre-fill the frame-buffer */
74         for (i=0; i<96; i++) {
75                 lcd_buf[i].Row = i+1;
76                 memfill(lcd_buf[i].Data, 0xff, 12);
77                 // lcd_buf[i].Data[0] = i;
78                 lcd_buf[i].Dummy = 0x00;
79         };
80 }
81
82 static void mw_lcd_write_line(const void *pData, unsigned char Size)
83 {
84 #ifndef xLCD_DMA
85         unsigned char Index;
86 #endif
87
88         LCD_CS_ASSERT();
89   
90 #ifdef xLCD_DMA
91         LcdDmaBusy = 1;
92
93         /* USCIB0 TXIFG is the DMA trigger
94          * DMACTL1 controls dma2 and [dma3]
95          */
96         DMACTL1 = DMA2TSEL_19;    
97     
98         DMA2SA = (unsigned int) pData;
99         DMA2DA = (unsigned int) &LCD_SPI_UCBxTXBUF;
100             
101         DMA2SZ = (unsigned int)Size;
102   
103         /* 
104          * single transfer, increment source address, source byte and dest byte,
105          * level sensitive, enable interrupt, clear interrupt flag
106          */
107         DMA2CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMALEVEL + DMAIE;  
108   
109         /* start the transfer */
110         DMA2CTL |= DMAEN;
111   
112         while (LcdDmaBusy)
113                 nop();
114 #else
115 //      debug_uart_tx("+wl1");
116         for ( Index = 0; Index < Size; Index++ ) {
117                 LCD_SPI_UCBxTXBUF = ((unsigned char *)pData)[Index];
118 //              debug_uart_tx(".");
119                 while (!(LCD_SPI_UCBxIFG & UCTXIFG)) {
120 //                      debug_uart_tx("+");
121                         nop();
122                 }
123         }
124 //      debug_uart_tx("\n+wl2\n");
125 #endif
126     
127         /* wait for shift to complete ( ~3 us ) */
128         while (LCD_SPI_UCBxSTAT & 0x01) {
129                 nop();
130 //              debug_uart_tx(".");
131         };
132
133         /* now the chip select can be deasserted */
134         LCD_CS_DEASSERT();
135 //      debug_uart_tx("\n-wl\n");
136 }
137
138
139 void mw_lcd_static_mode(void)
140 {
141         mw_lcd_write_line(LCD_STATIC_COMMAND, LCD_STATIC_CMD_SIZE);   
142 }
143
144 void mw_lcd_clear(void)
145 {
146         unsigned char i;
147
148         mw_lcd_write_line(LCD_CLEAR_COMMAND, LCD_CLEAR_CMD_SIZE);
149
150         /* pre-fill the frame-buffer */
151         for (i=0; i<96; i++) {
152                 memfill(lcd_buf[i].Data, 0xff, 12);
153         };
154 }
155
156 void mw_lcd_clear_fb(void)
157 {
158         unsigned char i;
159
160         /* pre-fill the frame-buffer */
161         for (i=0; i<96; i++) {
162 #if LCD_BLACK == 0
163                 memfill(lcd_buf[i].Data, 0xff, 12);
164 #else
165                 memfill(lcd_buf[i].Data, 0x00, 12);
166 #endif
167         };
168 }
169
170 #pragma vector=DMA_VECTOR
171 __interrupt void DMA_ISR (void)
172 {
173         switch (DMAIV) {
174         case 0:
175                 DMA0CTL &= ~DMAEN;      // disable
176                 DMA0CTL &= ~DMAIFG;     // clear IRQ flag
177                 debug_uart_tx("DMA0 IRQ\n");
178                 break;
179         case 2:
180                 debug_uart_tx("DMA1 IRQ\n");
181                 break;
182         case 4:
183                 debug_uart_tx("DMA2b IRQ\n");
184                 break;
185         case 6:
186                 DMA2CTL &= ~DMAEN;      // disable
187                 DMA2CTL &= ~DMAIFG;     // clear IRQ flag
188 #ifdef LCD_DMA
189                 LcdDmaBusy = 0;
190 #endif
191                 //LED7_TOGGLE();
192                 // debug_uart_tx("DMA2 IRQ\n");
193                 break;
194         }
195 }
196
197 /* writes the complete internal framebuffer to the LCD */
198 void mw_lcd_update_screen(void)
199 {
200 #ifndef LCD_DMA
201         unsigned int i,j;
202 #endif
203
204 //      debug_uart_tx("uscr1\n");
205
206         LCD_CS_ASSERT();
207
208         /* send WRITE command */
209         LCD_SPI_UCBxTXBUF = LCD_WRITE_CMD;
210         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
211                 nop();
212
213 //      debug_uart_tx("uscr2\n");
214
215 #ifdef LCD_DMA
216         LcdDmaBusy = 1;
217   
218         /* USCIB0 TXIFG is the DMA trigger
219          * DMACTL1 controls dma2 and [dma3]
220          */
221         DMACTL1 = DMA2TSEL_19;    
222
223         DMA2SA = (unsigned int) lcd_buf;
224         DMA2DA = (unsigned int) &LCD_SPI_UCBxTXBUF;
225             
226         DMA2SZ = 96 * sizeof(tLcdLine);
227   
228         /* 
229          * single transfer, increment source address, source byte and dest byte,
230          * level sensitive, enable interrupt, clear interrupt flag
231          */
232         DMA2CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMALEVEL + DMAIE;  
233   
234         /* start the transfer */
235         DMA2CTL |= DMAEN;
236
237 //      debug_uart_tx("uscr3\n");
238
239         // LED7_OFF();
240         while (LcdDmaBusy)
241                 nop();
242
243 //      debug_uart_tx("uscr4\n");
244 #else
245         for (i=0; i<96; i++) {
246                 for ( j = 0; j < sizeof(tLcdLine); j++ ) {
247                         LCD_SPI_UCBxTXBUF = ((unsigned char *)(&lcd_buf[i]))[j];
248                         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
249                                 nop();
250                 }
251         }
252 #endif
253
254         /* send final trailer byte */
255         LCD_SPI_UCBxTXBUF = 0x00;
256         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
257                 nop();
258
259 //      debug_uart_tx("uscr5\n");
260         /* wait for shift to complete ( ~3 us ) */
261         while (LCD_SPI_UCBxSTAT & 0x01)
262                 nop();
263
264 //      debug_uart_tx("uscr6\n");
265         LCD_CS_DEASSERT();
266
267         mw_lcd_static_mode();
268 }
269
270 void mw_lcd_draw_pixel(unsigned char x, unsigned char y, unsigned char color)
271 {
272         switch (color) {
273                 case 1:
274                         lcd_buf[y].Data[x/8] |= 1 << (x % 8);
275                         break;
276                 case 0:
277                         lcd_buf[y].Data[x/8] &= ~(1 << (x % 8));
278                         break;
279                 case 2:
280                         lcd_buf[y].Data[x/8] ^= 1 << (x % 8);
281                         break;
282         }
283 }
284