diff options
Diffstat (limited to 'firmware/drivers/lcd.c')
-rw-r--r-- | firmware/drivers/lcd.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/firmware/drivers/lcd.c b/firmware/drivers/lcd.c index 3f6acee301..aaa93b3385 100644 --- a/firmware/drivers/lcd.c +++ b/firmware/drivers/lcd.c | |||
@@ -173,3 +173,116 @@ void lcd_write(bool command, int byte) | |||
173 | : /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC), | 173 | : /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC), |
174 | /* %1 */ "z"(LCDR)); | 174 | /* %1 */ "z"(LCDR)); |
175 | } | 175 | } |
176 | |||
177 | |||
178 | /* A high performance function to write data to the display, | ||
179 | one or multiple bytes. | ||
180 | Ultimately, all calls to lcd_write(false, xxx) should be substituted by | ||
181 | this, it will be most efficient if the LCD buffer is tilted to have the | ||
182 | X row as consecutive bytes, so we can write a whole row */ | ||
183 | /* FixMe: somehow the red LED is affected by this, although I don't touch | ||
184 | any other bit. Therefore not used yet, except for lcd_blit() */ | ||
185 | void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode"))); | ||
186 | void lcd_write_data(unsigned char* p_bytes, int count) | ||
187 | { | ||
188 | do | ||
189 | { | ||
190 | unsigned byte; | ||
191 | unsigned sda1; /* precalculated SC=low,SD=1 */ | ||
192 | unsigned clk0sda0; /* precalculated SC and SD low */ | ||
193 | |||
194 | cli(); /* make port modifications atomic */ | ||
195 | |||
196 | /* precalculate the values for later bit toggling, init data write */ | ||
197 | asm ( | ||
198 | "mov.b @%2,%0\n" /* sda1 = PBDRL */ | ||
199 | "or %4,%0\n" /* sda1 |= LCD_DS | LCD_SD DS and SD high, */ | ||
200 | "and %3,%0\n" /* sda1 &= ~(LCD_CS | LCD_SC) CS and SC low */ | ||
201 | "mov %0,%1\n" /* sda1 -> clk0sda0 */ | ||
202 | "and %5,%1\n" /* clk0sda0 &= ~LCD_SD both low */ | ||
203 | "mov.b %1,@%2\n" /* PBDRL = clk0sda0 */ | ||
204 | : // outputs | ||
205 | /* %0 */ "=r"(sda1), | ||
206 | /* %1 */ "=r"(clk0sda0) | ||
207 | : // inputs | ||
208 | /* %2 */ "r"(LCDR), | ||
209 | /* %3 */ "r"(~(LCD_CS | LCD_SC)), | ||
210 | /* %4 */ "r"(LCD_DS | LCD_SD), | ||
211 | /* %5 */ "r"(~LCD_SD) | ||
212 | ); | ||
213 | |||
214 | byte = *p_bytes++ << 24; /* fetch to MSB position */ | ||
215 | |||
216 | /* unrolled loop to serialize the byte */ | ||
217 | asm ( | ||
218 | "mov %4,r0\n" /* we need &PBDRL in r0 for "or.b x,@(r0,gbr)" */ | ||
219 | |||
220 | "shll %0\n" /* shift the MSB into carry */ | ||
221 | "bf 1f\n" | ||
222 | "mov.b %1,@%4\n" /* if it was a "1": set SD high, SC low still */ | ||
223 | "1: \n" | ||
224 | "or.b %2, @(r0,gbr)\n" /* rise SC (independent of SD level) */ | ||
225 | "shll %0\n" /* shift for next round, now for longer hold time */ | ||
226 | "mov.b %3,@%4\n" /* SC and SD low again */ | ||
227 | |||
228 | "bf 1f\n" | ||
229 | "mov.b %1,@%4\n" | ||
230 | "1: \n" | ||
231 | "or.b %2, @(r0,gbr)\n" | ||
232 | "shll %0\n" | ||
233 | "mov.b %3,@%4\n" | ||
234 | |||
235 | "bf 1f\n" | ||
236 | "mov.b %1,@%4\n" | ||
237 | "1: \n" | ||
238 | "or.b %2, @(r0,gbr)\n" | ||
239 | "shll %0\n" | ||
240 | "mov.b %3,@%4\n" | ||
241 | |||
242 | "bf 1f\n" | ||
243 | "mov.b %1,@%4\n" | ||
244 | "1: \n" | ||
245 | "or.b %2, @(r0,gbr)\n" | ||
246 | "shll %0\n" | ||
247 | "mov.b %3,@%4\n" | ||
248 | |||
249 | "bf 1f\n" | ||
250 | "mov.b %1,@%4\n" | ||
251 | "1: \n" | ||
252 | "or.b %2, @(r0,gbr)\n" | ||
253 | "shll %0\n" | ||
254 | "mov.b %3,@%4\n" | ||
255 | |||
256 | "bf 1f\n" | ||
257 | "mov.b %1,@%4\n" | ||
258 | "1: \n" | ||
259 | "or.b %2, @(r0,gbr)\n" | ||
260 | "shll %0\n" | ||
261 | "mov.b %3,@%4\n" | ||
262 | |||
263 | "bf 1f\n" | ||
264 | "mov.b %1,@%4\n" | ||
265 | "1: \n" | ||
266 | "or.b %2, @(r0,gbr)\n" | ||
267 | "shll %0\n" | ||
268 | "mov.b %3,@%4\n" | ||
269 | |||
270 | "bf 1f\n" | ||
271 | "mov.b %1,@%4\n" | ||
272 | "1: \n" | ||
273 | "or.b %2, @(r0,gbr)\n" | ||
274 | |||
275 | "or.b %5, @(r0,gbr)\n" /* restore port */ | ||
276 | : | ||
277 | : /* %0 */ "r"(byte), | ||
278 | /* %1 */ "r"(sda1), | ||
279 | /* %2 */ "I"(LCD_SC), | ||
280 | /* %3 */ "r"(clk0sda0), | ||
281 | /* %4 */ "r"(LCDR), | ||
282 | /* %5 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC) | ||
283 | ); | ||
284 | |||
285 | sti(); | ||
286 | |||
287 | } while (--count); /* tail loop is faster */ | ||
288 | } | ||