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
16 #define LCD_STATIC_CMD 0x00
17 #define LCD_WRITE_CMD 0x01
18 #define LCD_CLEAR_CMD 0x04
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
26 /* the LCD frame buffer, 96 lines */
31 /* errata - DMA variables cannot be function scope */
33 static unsigned char LcdDmaBusy = 0;
37 void memfill(void *target, unsigned char val, unsigned int count)
40 *(unsigned char *)(target+count) = val;
44 void mw_lcd_init(void)
52 // DISABLE_LCD_ENABLE();
55 /* Put state machine in reset while it is configured */
56 LCD_SPI_UCBxCTL1 |= UCSWRST;
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
64 LCD_SPI_UCBxCTL0 |= UCMST+ UCCKPH + UCSYNC;
66 LCD_SPI_UCBxCTL1 |= UCSSEL_2;
67 LCD_SPI_UCBxBR0 = SPI_PRESCALE_L;
68 LCD_SPI_UCBxBR1 = SPI_PRESCALE_H;
71 LCD_SPI_UCBxCTL1 &= ~UCSWRST;
73 /* pre-fill the frame-buffer */
74 for (i=0; i<96; i++) {
76 memfill(lcd_buf[i].Data, 0xff, 12);
77 // lcd_buf[i].Data[0] = i;
78 lcd_buf[i].Dummy = 0x00;
82 static void mw_lcd_write_line(const void *pData, unsigned char Size)
93 /* USCIB0 TXIFG is the DMA trigger
94 * DMACTL1 controls dma2 and [dma3]
96 DMACTL1 = DMA2TSEL_19;
98 DMA2SA = (unsigned int) pData;
99 DMA2DA = (unsigned int) &LCD_SPI_UCBxTXBUF;
101 DMA2SZ = (unsigned int)Size;
104 * single transfer, increment source address, source byte and dest byte,
105 * level sensitive, enable interrupt, clear interrupt flag
107 DMA2CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMALEVEL + DMAIE;
109 /* start the transfer */
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("+");
124 // debug_uart_tx("\n+wl2\n");
127 /* wait for shift to complete ( ~3 us ) */
128 while (LCD_SPI_UCBxSTAT & 0x01) {
130 // debug_uart_tx(".");
133 /* now the chip select can be deasserted */
135 // debug_uart_tx("\n-wl\n");
139 void mw_lcd_static_mode(void)
141 mw_lcd_write_line(LCD_STATIC_COMMAND, LCD_STATIC_CMD_SIZE);
144 void mw_lcd_clear(void)
148 mw_lcd_write_line(LCD_CLEAR_COMMAND, LCD_CLEAR_CMD_SIZE);
150 /* pre-fill the frame-buffer */
151 for (i=0; i<96; i++) {
152 memfill(lcd_buf[i].Data, 0xff, 12);
156 void mw_lcd_clear_fb(void)
160 /* pre-fill the frame-buffer */
161 for (i=0; i<96; i++) {
163 memfill(lcd_buf[i].Data, 0xff, 12);
165 memfill(lcd_buf[i].Data, 0x00, 12);
170 #pragma vector=DMA_VECTOR
171 __interrupt void DMA_ISR (void)
175 DMA0CTL &= ~DMAEN; // disable
176 DMA0CTL &= ~DMAIFG; // clear IRQ flag
177 debug_uart_tx("DMA0 IRQ\n");
180 debug_uart_tx("DMA1 IRQ\n");
183 debug_uart_tx("DMA2b IRQ\n");
186 DMA2CTL &= ~DMAEN; // disable
187 DMA2CTL &= ~DMAIFG; // clear IRQ flag
192 // debug_uart_tx("DMA2 IRQ\n");
197 /* writes the complete internal framebuffer to the LCD */
198 void mw_lcd_update_screen(void)
204 // debug_uart_tx("uscr1\n");
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];
217 /* send WRITE command */
218 LCD_SPI_UCBxTXBUF = LCD_WRITE_CMD;
219 while (!(LCD_SPI_UCBxIFG & UCTXIFG))
222 // debug_uart_tx("uscr2\n");
227 /* USCIB0 TXIFG is the DMA trigger
228 * DMACTL1 controls dma2 and [dma3]
230 DMACTL1 = DMA2TSEL_19;
232 DMA2SA = (unsigned int) lcd_buf;
233 DMA2DA = (unsigned int) &LCD_SPI_UCBxTXBUF;
235 DMA2SZ = 96 * sizeof(tLcdLine);
238 * single transfer, increment source address, source byte and dest byte,
239 * level sensitive, enable interrupt, clear interrupt flag
241 DMA2CTL = DMADT_0 + DMASRCINCR_3 + DMASBDB + DMALEVEL + DMAIE;
243 /* start the transfer */
246 // debug_uart_tx("uscr3\n");
252 // debug_uart_tx("uscr4\n");
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))
263 /* send final trailer byte */
264 LCD_SPI_UCBxTXBUF = 0x00;
265 while (!(LCD_SPI_UCBxIFG & UCTXIFG))
268 // debug_uart_tx("uscr5\n");
269 /* wait for shift to complete ( ~3 us ) */
270 while (LCD_SPI_UCBxSTAT & 0x01)
273 // debug_uart_tx("uscr6\n");
276 mw_lcd_static_mode();
279 void mw_lcd_draw_pixel(const uint8_t x, const uint8_t y, const uint8_t color)
283 lcd_buf[y].Data[x/8] |= 1 << (x % 8);
286 lcd_buf[y].Data[x/8] &= ~(1 << (x % 8));
289 lcd_buf[y].Data[x/8] ^= 1 << (x % 8);