pwcdecode
annotate pwcdecode.c @ 1:4ea5d2920f89
made the timing more accurate
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 01 Nov 2013 21:33:14 +0200 |
parents | 050c04723d37 |
children |
rev | line source |
---|---|
nuclear@0 | 1 #define F_CLK 1000000 |
nuclear@0 | 2 #define F_CPU 1000000 |
nuclear@0 | 3 |
nuclear@0 | 4 #include <stdio.h> |
nuclear@0 | 5 #include <avr/io.h> |
nuclear@0 | 6 #include <avr/interrupt.h> |
nuclear@0 | 7 #include <util/delay.h> |
nuclear@0 | 8 |
nuclear@0 | 9 /* hardware setup |
nuclear@0 | 10 * - PORT D: data bits |
nuclear@0 | 11 * - PORT C |
nuclear@0 | 12 * bit 3: RS |
nuclear@0 | 13 * bit 4: R/W |
nuclear@0 | 14 * bit 5: E |
nuclear@0 | 15 */ |
nuclear@0 | 16 #define LCD_BUS_WIDTH 8 |
nuclear@0 | 17 |
nuclear@0 | 18 #define BIT_RS 3 |
nuclear@0 | 19 #define BIT_RW 4 |
nuclear@0 | 20 #define BIT_E 5 |
nuclear@0 | 21 |
nuclear@0 | 22 #define CMD_CLEAR 1 |
nuclear@0 | 23 #define CMD_RET (1 << 1) |
nuclear@0 | 24 #define CMD_ENTRY_MODE (1 << 2) |
nuclear@0 | 25 #define CMD_ONOFF (1 << 3) |
nuclear@0 | 26 #define CMD_SHIFT (1 << 4) |
nuclear@0 | 27 #define CMD_FUNC (1 << 5) |
nuclear@0 | 28 #define CMD_CGRAM_ADDR (1 << 6) |
nuclear@0 | 29 #define CMD_DDRAM_ADDR (1 << 7) |
nuclear@0 | 30 |
nuclear@0 | 31 #define FUNC_BUS_4BIT 0 |
nuclear@0 | 32 #define FUNC_BUS_8BIT (1 << 4) |
nuclear@0 | 33 #define FUNC_LINES_1 0 |
nuclear@0 | 34 #define FUNC_LINES_2 (1 << 3) |
nuclear@0 | 35 #define FUNC_FONT_5x8 0 |
nuclear@0 | 36 #define FUNC_FONT_5x11 (1 << 2) |
nuclear@0 | 37 |
nuclear@0 | 38 #define ONOFF_DISP (1 << 2) |
nuclear@0 | 39 #define ONOFF_CURSOR (1 << 1) |
nuclear@0 | 40 #define ONOFF_CURSOR_POS 1 |
nuclear@0 | 41 |
nuclear@0 | 42 void lcd_init(void); |
nuclear@0 | 43 void lcd_clear(void); |
nuclear@0 | 44 void lcd_set_cursor_addr(unsigned int addr); |
nuclear@0 | 45 void lcd_putchar(char c); |
nuclear@0 | 46 void lcd_putstr(const char *str); |
nuclear@0 | 47 int lcd_stream_write(char c, FILE *fp); |
nuclear@0 | 48 void lcd_wait_busy(void); |
nuclear@0 | 49 static void enable(void); |
nuclear@0 | 50 static void set_bit(int bit); |
nuclear@0 | 51 static void clear_bit(int bit); |
nuclear@0 | 52 void delay(int x); |
nuclear@0 | 53 |
nuclear@0 | 54 #define NSDELAY() asm volatile ("nop") |
nuclear@0 | 55 #define DEBUG(i) (PORTB = (1 << (i))) |
nuclear@0 | 56 |
nuclear@0 | 57 FILE stream_lcd = FDEV_SETUP_STREAM(lcd_stream_write, NULL, _FDEV_SETUP_WRITE); |
nuclear@0 | 58 |
nuclear@0 | 59 unsigned int pulse_time; |
nuclear@0 | 60 |
nuclear@0 | 61 int main(void) |
nuclear@0 | 62 { |
nuclear@0 | 63 stdout = stderr = &stream_lcd; |
nuclear@0 | 64 |
nuclear@0 | 65 DDRB = 0; /* set port B as input (bit 0 is used to measure pulse width) */ |
nuclear@0 | 66 PORTB = 0; /* disable pullups */ |
nuclear@0 | 67 |
nuclear@0 | 68 DDRD = 0xff; |
nuclear@0 | 69 DDRC = 0xfe; |
nuclear@0 | 70 PORTC = 0; /* disable pullups */ |
nuclear@0 | 71 |
nuclear@0 | 72 lcd_init(); |
nuclear@0 | 73 lcd_clear(); |
nuclear@0 | 74 |
nuclear@0 | 75 printf("initializing..."); |
nuclear@0 | 76 |
nuclear@0 | 77 TCCR1B |= (1 << ICES1); /* set first capture to occur on a rising edge */ |
nuclear@1 | 78 TCCR1B = (TCCR1B & 0xf8) | 2; /* /8 prescaling */ |
nuclear@0 | 79 TIMSK1 |= (1 << ICIE1); /* enable timer1 input capture interrupt */ |
nuclear@0 | 80 sei(); |
nuclear@0 | 81 |
nuclear@0 | 82 for(;;) { |
nuclear@0 | 83 lcd_set_cursor_addr(0); |
nuclear@0 | 84 printf("pulse time: %u us ", pulse_time); |
nuclear@0 | 85 lcd_set_cursor_addr(64); |
nuclear@1 | 86 printf("pos: %u %% ", (pulse_time - 1000) / 10); |
nuclear@0 | 87 _delay_ms(100); |
nuclear@0 | 88 } |
nuclear@0 | 89 return 0; |
nuclear@0 | 90 } |
nuclear@0 | 91 |
nuclear@0 | 92 ISR(TIMER1_CAPT_vect) |
nuclear@0 | 93 { |
nuclear@0 | 94 static int rising; |
nuclear@1 | 95 static unsigned int start_time; |
nuclear@0 | 96 |
nuclear@0 | 97 rising = !rising; |
nuclear@0 | 98 if(rising) { |
nuclear@1 | 99 /* start counting ... */ |
nuclear@1 | 100 start_time = ICR1; |
nuclear@0 | 101 /* and set a falling edge trigger */ |
nuclear@0 | 102 TCCR1B &= ~(1 << ICES1); |
nuclear@0 | 103 } else { |
nuclear@0 | 104 /* falling edge: calculate the time since the last rise */ |
nuclear@1 | 105 pulse_time = (ICR1 - start_time) * 8; /* 8x to cancel out prescaling */ |
nuclear@0 | 106 /* and set a rising edge trigger */ |
nuclear@0 | 107 TCCR1B |= 1 << ICES1; |
nuclear@1 | 108 |
nuclear@1 | 109 /* also clear the timer so it won't overflow */ |
nuclear@1 | 110 TCNT1 = 0; |
nuclear@0 | 111 } |
nuclear@0 | 112 } |
nuclear@0 | 113 |
nuclear@0 | 114 void lcd_write_byte(unsigned char byte) |
nuclear@0 | 115 { |
nuclear@0 | 116 #if LCD_BUS_WIDTH == 8 |
nuclear@0 | 117 DDRD = 0xff; |
nuclear@0 | 118 PORTD = byte; |
nuclear@0 | 119 #else |
nuclear@0 | 120 DDRD = (DDRD & 0xf0) | 0xf; |
nuclear@0 | 121 |
nuclear@0 | 122 PORTD = (PORTD & 0xf0) | ((byte >> 4) & 0xf); |
nuclear@0 | 123 PORTD = (PORTD & 0xf0) | (byte & 0xf); |
nuclear@0 | 124 #endif |
nuclear@0 | 125 } |
nuclear@0 | 126 |
nuclear@0 | 127 unsigned char lcd_read_byte(void) |
nuclear@0 | 128 { |
nuclear@0 | 129 #if LCD_BUS_WIDTH == 8 |
nuclear@0 | 130 DDRD = 0; |
nuclear@0 | 131 PORTD = 0; /* disable pull-ups */ |
nuclear@0 | 132 |
nuclear@0 | 133 return PIND; |
nuclear@0 | 134 #else |
nuclear@0 | 135 unsigned char byte; |
nuclear@0 | 136 |
nuclear@0 | 137 DDRD = DDRD & 0xf0; |
nuclear@0 | 138 PORTD &= 0xf0; /* disable pull-ups */ |
nuclear@0 | 139 |
nuclear@0 | 140 byte = (PIND & 0xf) << 4; |
nuclear@0 | 141 return byte | (PIND & 0xf); |
nuclear@0 | 142 #endif |
nuclear@0 | 143 } |
nuclear@0 | 144 |
nuclear@0 | 145 void lcd_init(void) |
nuclear@0 | 146 { |
nuclear@0 | 147 /* make sure the display has time to boot up */ |
nuclear@0 | 148 _delay_ms(20); |
nuclear@0 | 149 |
nuclear@0 | 150 clear_bit(BIT_RW); |
nuclear@0 | 151 |
nuclear@0 | 152 clear_bit(BIT_E); |
nuclear@0 | 153 clear_bit(BIT_RS); |
nuclear@0 | 154 #if LCD_BUS_WIDTH == 8 |
nuclear@0 | 155 lcd_write_byte(CMD_FUNC | FUNC_BUS_8BIT | FUNC_LINES_2 | FUNC_FONT_5x8); |
nuclear@0 | 156 #else |
nuclear@0 | 157 lcd_write_byte(CMD_FUNC | FUNC_BUS_4BIT | FUNC_LINES_2 | FUNC_FONT_5x8); |
nuclear@0 | 158 #endif |
nuclear@0 | 159 enable(); |
nuclear@0 | 160 lcd_wait_busy(); |
nuclear@0 | 161 |
nuclear@0 | 162 clear_bit(BIT_RS); |
nuclear@0 | 163 lcd_write_byte(CMD_ONOFF | ONOFF_DISP); |
nuclear@0 | 164 enable(); |
nuclear@0 | 165 lcd_wait_busy(); |
nuclear@0 | 166 |
nuclear@0 | 167 clear_bit(BIT_RS); |
nuclear@0 | 168 lcd_write_byte(CMD_ENTRY_MODE | (1 << 1)); |
nuclear@0 | 169 enable(); |
nuclear@0 | 170 lcd_wait_busy(); |
nuclear@0 | 171 } |
nuclear@0 | 172 |
nuclear@0 | 173 void lcd_clear(void) |
nuclear@0 | 174 { |
nuclear@0 | 175 clear_bit(BIT_RW); |
nuclear@0 | 176 |
nuclear@0 | 177 clear_bit(BIT_E); |
nuclear@0 | 178 clear_bit(BIT_RS); |
nuclear@0 | 179 lcd_write_byte(CMD_CLEAR); |
nuclear@0 | 180 enable(); |
nuclear@0 | 181 lcd_wait_busy(); |
nuclear@0 | 182 } |
nuclear@0 | 183 |
nuclear@0 | 184 void lcd_set_cursor_addr(unsigned int addr) |
nuclear@0 | 185 { |
nuclear@0 | 186 clear_bit(BIT_RW); |
nuclear@0 | 187 |
nuclear@0 | 188 clear_bit(BIT_E); |
nuclear@0 | 189 clear_bit(BIT_RS); |
nuclear@0 | 190 lcd_write_byte(CMD_DDRAM_ADDR | addr); |
nuclear@0 | 191 enable(); |
nuclear@0 | 192 lcd_wait_busy(); |
nuclear@0 | 193 } |
nuclear@0 | 194 |
nuclear@0 | 195 void lcd_putchar(char c) |
nuclear@0 | 196 { |
nuclear@0 | 197 clear_bit(BIT_RW); |
nuclear@0 | 198 |
nuclear@0 | 199 set_bit(BIT_RS); |
nuclear@0 | 200 lcd_write_byte(c); |
nuclear@0 | 201 enable(); |
nuclear@0 | 202 lcd_wait_busy(); |
nuclear@0 | 203 } |
nuclear@0 | 204 |
nuclear@0 | 205 void lcd_putstr(const char *str) |
nuclear@0 | 206 { |
nuclear@0 | 207 while(*str) { |
nuclear@0 | 208 lcd_putchar(*str++); |
nuclear@0 | 209 } |
nuclear@0 | 210 } |
nuclear@0 | 211 |
nuclear@0 | 212 int lcd_stream_write(char c, FILE *fp) |
nuclear@0 | 213 { |
nuclear@0 | 214 /* TODO terminal shit handling */ |
nuclear@0 | 215 lcd_putchar(c); |
nuclear@0 | 216 return 0; |
nuclear@0 | 217 } |
nuclear@0 | 218 |
nuclear@0 | 219 void lcd_wait_busy(void) |
nuclear@0 | 220 { |
nuclear@0 | 221 unsigned char data; |
nuclear@0 | 222 |
nuclear@0 | 223 do { |
nuclear@0 | 224 NSDELAY(); |
nuclear@0 | 225 clear_bit(BIT_E); |
nuclear@0 | 226 clear_bit(BIT_RS); |
nuclear@0 | 227 set_bit(BIT_RW); |
nuclear@0 | 228 /*PIND = 0xff;*/ |
nuclear@0 | 229 |
nuclear@0 | 230 NSDELAY(); |
nuclear@0 | 231 set_bit(BIT_E); |
nuclear@0 | 232 NSDELAY(); |
nuclear@0 | 233 data = lcd_read_byte(); |
nuclear@0 | 234 clear_bit(BIT_E); |
nuclear@0 | 235 clear_bit(BIT_RW); |
nuclear@0 | 236 |
nuclear@0 | 237 } while(data & (1 << 7)); |
nuclear@0 | 238 } |
nuclear@0 | 239 |
nuclear@0 | 240 static void enable(void) |
nuclear@0 | 241 { |
nuclear@0 | 242 NSDELAY(); |
nuclear@0 | 243 set_bit(BIT_E); |
nuclear@0 | 244 NSDELAY(); |
nuclear@0 | 245 clear_bit(BIT_E); |
nuclear@0 | 246 NSDELAY(); |
nuclear@0 | 247 } |
nuclear@0 | 248 |
nuclear@0 | 249 static void set_bit(int bit) |
nuclear@0 | 250 { |
nuclear@0 | 251 PORTC |= 1 << bit; |
nuclear@0 | 252 } |
nuclear@0 | 253 |
nuclear@0 | 254 static void clear_bit(int bit) |
nuclear@0 | 255 { |
nuclear@0 | 256 PORTC &= ~(1 << bit); |
nuclear@0 | 257 } |
nuclear@0 | 258 |
nuclear@0 | 259 |
nuclear@0 | 260 void delay(int x) |
nuclear@0 | 261 { |
nuclear@0 | 262 int i, j; |
nuclear@0 | 263 |
nuclear@0 | 264 while(x-- > 0) { |
nuclear@0 | 265 for(i=0; i<90; i++) { |
nuclear@0 | 266 for(j=0; j<6; j++) { |
nuclear@0 | 267 asm volatile("nop"); |
nuclear@0 | 268 } |
nuclear@0 | 269 } |
nuclear@0 | 270 } |
nuclear@0 | 271 } |