1 | /******************************************************************************* |
---|
2 | * lcdr_user.c - Controleur pour LCd HD44780 ( 20x4 ) |
---|
3 | ******************************************************************************/ |
---|
4 | |
---|
5 | #include <stdio.h> |
---|
6 | #include <stdlib.h> |
---|
7 | #include <unistd.h> |
---|
8 | #include <stdint.h> |
---|
9 | #include <string.h> |
---|
10 | #include <sys/types.h> |
---|
11 | #include <sys/stat.h> |
---|
12 | #include <fcntl.h> |
---|
13 | #include <sys/mman.h> |
---|
14 | |
---|
15 | /******************************************************************************* |
---|
16 | * GPIO Pins |
---|
17 | ******************************************************************************/ |
---|
18 | #define RS 7 |
---|
19 | #define E 27 |
---|
20 | #define D4 22 |
---|
21 | #define D5 23 |
---|
22 | #define D6 24 |
---|
23 | #define D7 25 |
---|
24 | |
---|
25 | #define GPIO_INPUT 0 |
---|
26 | #define GPIO_OUTPUT 1 |
---|
27 | |
---|
28 | #define RPI_BLOCK_SIZE 0xB4 |
---|
29 | #define RPI_GPIO_BASE 0x20200000 |
---|
30 | |
---|
31 | struct gpio_s |
---|
32 | { |
---|
33 | uint32_t gpfsel[7]; |
---|
34 | uint32_t gpset[3]; |
---|
35 | uint32_t gpclr[3]; |
---|
36 | uint32_t gplev[3]; |
---|
37 | uint32_t gpeds[3]; |
---|
38 | uint32_t gpren[3]; |
---|
39 | uint32_t gpfen[3]; |
---|
40 | uint32_t gphen[3]; |
---|
41 | uint32_t gplen[3]; |
---|
42 | uint32_t gparen[3]; |
---|
43 | uint32_t gpafen[3]; |
---|
44 | uint32_t gppud[1]; |
---|
45 | uint32_t gppudclk[3]; |
---|
46 | uint32_t test[1]; |
---|
47 | }; |
---|
48 | volatile struct gpio_s* gpio_regs; |
---|
49 | |
---|
50 | /******************************************************************************* |
---|
51 | * GPIO Operations |
---|
52 | ******************************************************************************/ |
---|
53 | |
---|
54 | int gpio_setup ( void ){ |
---|
55 | |
---|
56 | int mmap_fd = open ("/dev/mem", O_RDWR | O_SYNC ); |
---|
57 | if ( mmap_fd < 0 ) { |
---|
58 | return -1; |
---|
59 | } |
---|
60 | |
---|
61 | gpio_regs = mmap ( NULL, RPI_BLOCK_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, mmap_fd, RPI_GPIO_BASE ); |
---|
62 | if ( gpio_regs == MAP_FAILED ) { |
---|
63 | close ( mmap_fd ); |
---|
64 | return -1; |
---|
65 | } |
---|
66 | |
---|
67 | return 0; |
---|
68 | } |
---|
69 | |
---|
70 | void gpio_teardown ( void ){ |
---|
71 | munmap((void*)gpio_regs, RPI_BLOCK_SIZE); |
---|
72 | } |
---|
73 | |
---|
74 | |
---|
75 | void gpio_config(int gpio, int value) |
---|
76 | { |
---|
77 | gpio_regs->gpfsel[gpio/10] = ( gpio_regs->gpfsel[gpio/10] & ~(0x7 << ((gpio % 10) * 3)) ) |
---|
78 | | (value << ((gpio % 10) * 3)); |
---|
79 | } |
---|
80 | |
---|
81 | void gpio_update(int gpio, int value) |
---|
82 | { |
---|
83 | if( value ) |
---|
84 | gpio_regs->gpset[gpio/32] = (0x1 << (gpio % 32) ); |
---|
85 | else |
---|
86 | gpio_regs->gpclr[gpio/32] = (0x1 << (gpio % 32) ); |
---|
87 | } |
---|
88 | |
---|
89 | /******************************************************************************* |
---|
90 | * LCD's Instructions ( source = doc ) |
---|
91 | ******************************************************************************/ |
---|
92 | |
---|
93 | #define B_0000 0 |
---|
94 | #define B_0001 1 |
---|
95 | #define B_0010 2 |
---|
96 | #define B_0011 3 |
---|
97 | #define B_0100 4 |
---|
98 | #define B_0101 5 |
---|
99 | #define B_0110 6 |
---|
100 | #define B_0111 7 |
---|
101 | #define B_1000 8 |
---|
102 | #define B_1001 9 |
---|
103 | #define B_1010 a |
---|
104 | #define B_1011 b |
---|
105 | #define B_1100 c |
---|
106 | #define B_1101 d |
---|
107 | #define B_1110 e |
---|
108 | #define B_1111 f |
---|
109 | |
---|
110 | /* On veut definir une macro HEX() |
---|
111 | * qui prend en argument deux nombres de 4 bits exprimes en binaire |
---|
112 | * representant resp. les 4 bits de poids fort et les 4 bits de poids faible d'un entier sur 8bits |
---|
113 | * qui rend l'entier. |
---|
114 | * p. ex: HEX(0000,0010) rend 2 |
---|
115 | * p. ex: HEX(0001,0000) rend 16 |
---|
116 | * |
---|
117 | * QUESTION: expliquez comment ca marche .... |
---|
118 | */ |
---|
119 | #define __HEX(h,l) 0x##h##l |
---|
120 | #define _HEX(h,l) __HEX(h,l) |
---|
121 | #define HEX(h,l) _HEX(B_##h,B_##l) |
---|
122 | |
---|
123 | /* QUESTION: que fait cette macro ? |
---|
124 | */ |
---|
125 | #define BIT(b,n) (((n)>>(b))&1) |
---|
126 | |
---|
127 | /* commands */ |
---|
128 | #define LCD_CLEARDISPLAY HEX(0000,0001) |
---|
129 | #define LCD_RETURNHOME HEX(0000,0010) |
---|
130 | #define LCD_ENTRYMODESET HEX(0000,0100) |
---|
131 | #define LCD_DISPLAYCONTROL HEX(0000,1000) |
---|
132 | #define LCD_CURSORSHIFT HEX(0001,0000) |
---|
133 | #define LCD_FUNCTIONSET HEX(0010,0000) |
---|
134 | #define LCD_SETCGRAMADDR HEX(0100,0000) |
---|
135 | #define LCD_SETDDRAMADDR HEX(1000,0000) |
---|
136 | |
---|
137 | /* flags for display entry mode : combine with LCD_ENTRYMODESET */ |
---|
138 | #define LCD_EM_RIGHT HEX(0000,0000) |
---|
139 | #define LCD_EM_LEFT HEX(0000,0010) |
---|
140 | #define LCD_EM_DISPLAYSHIFT HEX(0000,0001) |
---|
141 | #define LCD_EM_DISPLAYNOSHIFT HEX(0000,0000) |
---|
142 | |
---|
143 | /* flags for display on/off control : combine with LCD_DISPLAYCONTROL */ |
---|
144 | #define LCD_DC_DISPLAYON HEX(0000,0100) |
---|
145 | #define LCD_DC_DISPLAYOFF HEX(0000,0000) |
---|
146 | #define LCD_DC_CURSORON HEX(0000,0010) |
---|
147 | #define LCD_DC_CURSOROFF HEX(0000,0000) |
---|
148 | #define LCD_DC_BLINKON HEX(0000,0001) |
---|
149 | #define LCD_DC_BLINKOFF HEX(0000,0000) |
---|
150 | |
---|
151 | /* flags for display/cursor shift : combine with LCD_CURSORSHIFT */ |
---|
152 | #define LCD_CS_DISPLAYMOVE HEX(0000,1000) |
---|
153 | #define LCD_CS_CURSORMOVE HEX(0000,0000) |
---|
154 | #define LCD_CS_MOVERIGHT HEX(0000,0100) |
---|
155 | #define LCD_CS_MOVELEFT HEX(0000,0000) |
---|
156 | |
---|
157 | /* flags for function set : combine with LCD_FUNCTIONSET */ |
---|
158 | #define LCD_FS_8BITMODE HEX(0001,0000) |
---|
159 | #define LCD_FS_4BITMODE HEX(0000,0000) |
---|
160 | #define LCD_FS_2LINE HEX(0000,1000) |
---|
161 | #define LCD_FS_1LINE HEX(0000,0000) |
---|
162 | #define LCD_FS_5x10DOTS HEX(0000,0100) |
---|
163 | #define LCD_FS_5x8DOTS HEX(0000,0000) |
---|
164 | |
---|
165 | /******************************************************************************* |
---|
166 | * LCD's Operations |
---|
167 | ******************************************************************************/ |
---|
168 | |
---|
169 | /* generate E signal */ |
---|
170 | void lcd_strobe(void) |
---|
171 | { |
---|
172 | /* A completer */ |
---|
173 | } |
---|
174 | |
---|
175 | /* send 4bits to LCD */ |
---|
176 | void lcd_write4bits(int data) |
---|
177 | { |
---|
178 | /* first 4 bits */ |
---|
179 | gpio_update(D7, BIT(7,data)); |
---|
180 | /* a completer */ |
---|
181 | lcd_strobe(); |
---|
182 | |
---|
183 | /* second 4 bits */ |
---|
184 | /* a completer */ |
---|
185 | lcd_strobe(); |
---|
186 | usleep(50); /* le délai minimum est de 37us */ |
---|
187 | } |
---|
188 | |
---|
189 | void lcd_command(int cmd) |
---|
190 | { |
---|
191 | gpio_update(RS, 0); |
---|
192 | lcd_write4bits(cmd); |
---|
193 | usleep(2000); /* delai nécessaire pour certaines commandes */ |
---|
194 | } |
---|
195 | |
---|
196 | void lcd_data(int character) |
---|
197 | { |
---|
198 | gpio_update(RS, 1); |
---|
199 | lcd_write4bits(character); |
---|
200 | } |
---|
201 | |
---|
202 | /* initialization |
---|
203 | * Question : commenter ces initialisations: |
---|
204 | * |
---|
205 | * LCD_FUNCTIONSET | LCD_FS_4BITMODE | LCD_FS_2LINE | LCD_FS_5x8DOTS |
---|
206 | * LCD_DISPLAYCONTROL | LCD_DC_DISPLAYON | LCD_DC_CURSOROFF |
---|
207 | * LCD_ENTRYMODESET | LCD_EM_RIGHT | LCD_EM_DISPLAYNOSHIFT |
---|
208 | */ |
---|
209 | void lcd_init(void) |
---|
210 | { |
---|
211 | gpio_update(E, 0); |
---|
212 | lcd_command(HEX(0011,0011)); /* initialization */ |
---|
213 | lcd_command(HEX(0011,0010)); /* initialization */ |
---|
214 | lcd_command(LCD_FUNCTIONSET | LCD_FS_/* a completer */ ); |
---|
215 | lcd_command(LCD_DISPLAYCONTROL | LCD_DC_/* a completer */ ); |
---|
216 | lcd_command(LCD_ENTRYMODESET | LCD_EM_/* a completer */ ); |
---|
217 | } |
---|
218 | |
---|
219 | void lcd_clear(void) |
---|
220 | { |
---|
221 | lcd_command(LCD_CLEARDISPLAY); |
---|
222 | lcd_command(LCD_RETURNHOME); |
---|
223 | } |
---|
224 | |
---|
225 | void lcd_message(char* txt) |
---|
226 | { |
---|
227 | int i, j; |
---|
228 | for(i=0; i<20 && i<strlen(txt); i++){ |
---|
229 | lcd_data(txt[i]); |
---|
230 | } |
---|
231 | } |
---|
232 | /******************************************************************************* |
---|
233 | * Finally, the main function |
---|
234 | ******************************************************************************/ |
---|
235 | int main(int argc, char** argv) |
---|
236 | { |
---|
237 | /* arg */ |
---|
238 | if( argc < 2 ){ |
---|
239 | fprintf(stderr, "ERROR: must take a string as argument\n"); |
---|
240 | exit(1); |
---|
241 | } |
---|
242 | |
---|
243 | /* Retreive the mapped GPIO memory */ |
---|
244 | if( gpio_setup() == -1 ){ |
---|
245 | perror("ERROR: gpio_setup\n"); |
---|
246 | exit(1); |
---|
247 | } |
---|
248 | |
---|
249 | /* Setting up GPIOs to output */ |
---|
250 | gpio_config(RS, GPIO_OUTPUT); |
---|
251 | gpio_config(E , GPIO_OUTPUT); |
---|
252 | gpio_config(D4, GPIO_OUTPUT); |
---|
253 | gpio_config(D5, GPIO_OUTPUT); |
---|
254 | gpio_config(D6, GPIO_OUTPUT); |
---|
255 | gpio_config(D7, GPIO_OUTPUT); |
---|
256 | |
---|
257 | /* initialization */ |
---|
258 | lcd_init(); |
---|
259 | lcd_clear(); |
---|
260 | |
---|
261 | /* print app argument */ |
---|
262 | lcd_message(argv[1]); |
---|
263 | |
---|
264 | /* Release the GPIO memory mapping */ |
---|
265 | gpio_teardown(); |
---|
266 | |
---|
267 | return 0; |
---|
268 | } |
---|