]> git.karo-electronics.de Git - oswald.git/blob - metawatch/mw_lcd.c
Some minor improvements.
[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         // invert the buffer
207         if (0) {
208                 for (i=0; i<96; i++) {
209                         for ( j = 0; j < 12; j++ ) {
210                                 lcd_buf[i].Data[j] = ~lcd_buf[i].Data[j];
211                         }
212                 }
213         }
214
215         LCD_CS_ASSERT();
216
217         /* send WRITE command */
218         LCD_SPI_UCBxTXBUF = LCD_WRITE_CMD;
219         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
220                 nop();
221
222 //      debug_uart_tx("uscr2\n");
223
224 #ifdef LCD_DMA
225         LcdDmaBusy = 1;
226   
227         /* USCIB0 TXIFG is the DMA trigger
228          * DMACTL1 controls dma2 and [dma3]
229          */
230         DMACTL1 = DMA2TSEL_19;    
231
232         DMA2SA = (unsigned int) lcd_buf;
233         DMA2DA = (unsigned int) &LCD_SPI_UCBxTXBUF;
234             
235         DMA2SZ = 96 * sizeof(tLcdLine);
236   
237         /* 
238          * single transfer, increment source address, source byte and dest byte,
239          * level sensitive, enable interrupt, clear interrupt flag
240          */
241         DMA2CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMALEVEL + DMAIE;  
242   
243         /* start the transfer */
244         DMA2CTL |= DMAEN;
245
246 //      debug_uart_tx("uscr3\n");
247
248         // LED7_OFF();
249         while (LcdDmaBusy)
250                 nop();
251
252 //      debug_uart_tx("uscr4\n");
253 #else
254         for (i=0; i<96; i++) {
255                 for ( j = 0; j < sizeof(tLcdLine); j++ ) {
256                         LCD_SPI_UCBxTXBUF = ((unsigned char *)(&lcd_buf[i]))[j];
257                         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
258                                 nop();
259                 }
260         }
261 #endif
262
263         /* send final trailer byte */
264         LCD_SPI_UCBxTXBUF = 0x00;
265         while (!(LCD_SPI_UCBxIFG & UCTXIFG))
266                 nop();
267
268 //      debug_uart_tx("uscr5\n");
269         /* wait for shift to complete ( ~3 us ) */
270         while (LCD_SPI_UCBxSTAT & 0x01)
271                 nop();
272
273 //      debug_uart_tx("uscr6\n");
274         LCD_CS_DEASSERT();
275
276         mw_lcd_static_mode();
277 }
278
279 void mw_lcd_draw_pixel(const uint8_t x, const uint8_t y, const uint8_t color)
280 {
281         switch (color) {
282                 case 1:
283                         lcd_buf[y].Data[x/8] |= 1 << (x % 8);
284                         break;
285                 case 0:
286                         lcd_buf[y].Data[x/8] &= ~(1 << (x % 8));
287                         break;
288                 case 2:
289                         lcd_buf[y].Data[x/8] ^= 1 << (x % 8);
290                         break;
291         }
292 }
293