summaryrefslogtreecommitdiff
path: root/firmware/drivers/lcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/drivers/lcd.c')
-rw-r--r--firmware/drivers/lcd.c113
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() */
185void lcd_write_data(unsigned char* p_bytes, int count) __attribute__ ((section (".icode")));
186void 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}