FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
lcd5110.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
41#ifndef LC5110_HH
42#define LC5110_HH
43
44#include <string.h>
45
46#include "../bits.h"
47#include "../flash.h"
48#include "../gpio.h"
49#include "../spi.h"
50#include "../time.h"
51#include "display.h"
52#include "font.h"
53
54namespace devices::display
55{
57 enum class TemperatureCoefficient : uint8_t
58 {
60 TC0_1mV_K = 0x04,
62 TC1_9mV_K = 0x05,
64 TC2_17mV_K = 0x06,
66 TC3_24mV_K = 0x07
67 };
68
70 // Forward declaration to allow traits definition
71 template<board::DigitalPin, board::DigitalPin, board::DigitalPin> class LCD5110;
72 // Traits for Nokia displays
73 template<board::DigitalPin SCE, board::DigitalPin DC, board::DigitalPin RST>
74 struct DisplayDeviceTrait<LCD5110<SCE, DC, RST>> :
75 DisplayDeviceTrait_impl<bool, 84, 48, true, true> {};
77
115 template<board::DigitalPin SCE, board::DigitalPin DC, board::DigitalPin RST> class LCD5110 :
116 public spi::SPIDevice<SCE, spi::ChipSelect::ACTIVE_LOW, spi::compute_clockrate(4'000'000UL)>
117 {
118 private:
120 static constexpr uint8_t WIDTH = TRAITS::WIDTH;
121 static constexpr uint8_t HEIGHT = TRAITS::HEIGHT;
123
124 public:
129 void reset()
130 {
131 // Reset device according to datasheet
135 }
136
143 void set_display_bias(uint8_t bias = DEFAULT_BIAS)
144 {
145 if (bias > MAX_BIAS) bias = MAX_BIAS;
146 this->start_transfer();
147 send_command_(FUNCTION_SET_MASK | FUNCTION_SET_EXTENDED);
148 send_command_(EXTENDED_SET_BIAS | bias);
149 send_command_(FUNCTION_SET_MASK);
150 this->end_transfer();
151 }
152
159 void set_display_contrast(uint8_t contrast = DEFAULT_VOP)
160 {
161 if (contrast > MAX_VOP) contrast = MAX_VOP;
162 this->start_transfer();
163 send_command_(FUNCTION_SET_MASK | FUNCTION_SET_EXTENDED);
164 send_command_(EXTENDED_SET_VOP | contrast);
165 send_command_(FUNCTION_SET_MASK);
166 this->end_transfer();
167 }
168
177 {
178 this->start_transfer();
179 send_command_(FUNCTION_SET_MASK | FUNCTION_SET_EXTENDED);
180 send_command_(EXTENDED_SET_BIAS | uint8_t(coef));
181 send_command_(FUNCTION_SET_MASK);
182 this->end_transfer();
183 }
184
189 {
190 send_command(FUNCTION_SET_MASK | FUNCTION_SET_POWER_DOWN);
191 }
192
197 void power_up()
198 {
199 send_command(FUNCTION_SET_MASK);
200 }
201
207 void blank()
208 {
209 send_command(DISPLAY_CONTROL_MASK | DISPLAY_CONTROL_BLANK);
210 }
211
217 void full()
218 {
219 send_command(DISPLAY_CONTROL_MASK | DISPLAY_CONTROL_FULL);
220 }
221
226 void invert()
227 {
228 send_command(DISPLAY_CONTROL_MASK | DISPLAY_CONTROL_INVERSE);
229 }
230
236 void normal()
237 {
238 send_command(DISPLAY_CONTROL_MASK | DISPLAY_CONTROL_NORMAL);
239 }
240
241 protected:
243 LCD5110()
244 {
245 erase();
246 }
247
248 void erase()
249 {
250 memset(display_, 0, sizeof(display_));
251 }
252
253 // NOTE Coordinates must have been first verified by caller
254 bool set_pixel(uint8_t x, uint8_t y, const DRAW_CONTEXT& context)
255 {
256 // Convert to (r,c)
257 const uint8_t c = x;
258 const uint8_t r = y / ROW_HEIGHT;
259 const uint8_t offset = y % ROW_HEIGHT;
260 uint8_t mask = bits::BV8(offset);
261 // Get pointer to pixel byte
262 uint8_t* pix_column = get_display(r, c);
263 // Evaluate final pixel color based on color_ and mode_
264 const bool current = (*pix_column & mask);
265 const bool dest = context.draw_mode().pixel_op(current);
266
267 // Based on calculated color, set pixel
268 if (dest)
269 {
270 if (current) return false;
271 *pix_column |= mask;
272 }
273 else
274 {
275 if (!current) return false;
276 *pix_column &= uint8_t(~mask);
277 }
278 return true;
279 }
280
281 bool is_valid_char_xy(UNUSED uint8_t x, uint8_t y)
282 {
283 return (y % ROW_HEIGHT) == 0;
284 }
285
286 // NOTE Coordinates must have been first verified by caller
287 uint8_t write_char(uint8_t x, uint8_t y, uint16_t glyph_ref, const DRAW_CONTEXT& context)
288 {
289 // Check column and row not out of range for characters!
290 const uint8_t width = context.font().width();
291 uint8_t row = y / ROW_HEIGHT;
292 const uint8_t col = x;
293 bool add_interchar_space = ((col + width + 1) < WIDTH);
294
295 uint8_t glyph_index = 0;
296 for (uint8_t glyph_row = 0; glyph_row < context.font().glyph_rows(); ++glyph_row)
297 {
298 // Get pointer to first byte in row to write in display buffer
299 uint8_t* display_ptr = get_display(row, col);
300
301 for (uint8_t i = 0; i <= width; ++i)
302 {
303 const bool space_column = (i == width);
304 uint8_t pixel_bar = 0x00;
305 if (!space_column)
306 pixel_bar = context.font().get_char_glyph_byte(glyph_ref, glyph_index);
307 if ((!space_column) || add_interchar_space)
308 *display_ptr = context.draw_mode().bw_pixels_op(pixel_bar, *display_ptr);
309 ++display_ptr;
310 ++glyph_index;
311 }
312 ++row;
313 }
314
315 // Return actual width writtent to display
316 return width + (add_interchar_space ? 1 : 0);
317 }
318
319 // Copy invalidated rectangle of display map onto the device
320 void update(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2)
321 {
322 const uint8_t size = (x2 - x1 + 1);
323 const uint8_t xmin = x1;
324 const uint8_t ymin = y1 / ROW_HEIGHT;
325 const uint8_t ymax = y2 / ROW_HEIGHT;
326 this->start_transfer();
327 for (uint8_t y = ymin; y <= ymax; ++y)
328 {
329 set_rc_(y, xmin);
330 dc_.set();
331 const uint8_t* display = get_display(y, xmin);
332 this->transfer(display, size);
333 }
334 this->end_transfer();
335 }
337
338 private:
339 // Internal organization of Nokia pixmap buffer (1 byte = 8 vertical pixels)
340 static constexpr uint8_t ROW_HEIGHT = 8;
341
342 // Masks for Nokia commands
343 static constexpr uint8_t FUNCTION_SET_MASK = bits::BV8(5);
344 static constexpr uint8_t FUNCTION_SET_POWER_DOWN = bits::BV8(2);
345 static constexpr uint8_t FUNCTION_SET_EXTENDED = bits::BV8(0);
346
347 static constexpr uint8_t EXTENDED_SET_BIAS = bits::BV8(4);
348 static constexpr uint8_t EXTENDED_SET_VOP = bits::BV8(7);
349
350 static constexpr uint8_t DISPLAY_CONTROL_MASK = bits::BV8(3);
351 static constexpr uint8_t DISPLAY_CONTROL_BLANK = 0;
352 static constexpr uint8_t DISPLAY_CONTROL_NORMAL = bits::BV8(2);
353 static constexpr uint8_t DISPLAY_CONTROL_FULL = bits::BV8(0);
354 static constexpr uint8_t DISPLAY_CONTROL_INVERSE = bits::BV8(0, 2);
355
356 static constexpr uint8_t SET_ROW_ADDRESS = bits::BV8(6);
357 static constexpr uint8_t SET_COL_ADDRESS = bits::BV8(7);
358
359 // Masks for bias and operation voltage (i.e. contrast)
360 static constexpr uint8_t MAX_BIAS = 0x07;
361 static constexpr uint8_t DEFAULT_BIAS = 0x04;
362 static constexpr uint8_t MAX_VOP = 0x7F;
363 static constexpr uint8_t DEFAULT_VOP = 40;
364
365 void send_command_(uint8_t command)
366 {
367 dc_.clear();
368 this->transfer(command);
369 }
370
371 void send_command(uint8_t command)
372 {
373 this->start_transfer();
374 send_command_(command);
375 this->end_transfer();
376 }
377
378 void set_rc_(uint8_t r, uint8_t c)
379 {
380 dc_.clear();
381 this->transfer(r | SET_ROW_ADDRESS);
382 this->transfer(c | SET_COL_ADDRESS);
383 }
384
385 // Get a pointer to display byte at (r,c) coordinates
386 // (r,c) must be valid coordinates in pixmap
387 uint8_t* get_display(uint8_t r, uint8_t c)
388 {
389 return &display_[r * WIDTH + c];
390 }
391 const uint8_t* get_display(uint8_t r, uint8_t c) const
392 {
393 return &display_[r * WIDTH + c];
394 }
395
396 // Display map (copy of chip display map)
397 // Format: R1C1 R1C2 ... R1Cn
398 // R2C1 R2C2 ... R2Cn
399 // ...
400 // RpC1 RpC2 ... RpCn
401 uint8_t display_[HEIGHT * WIDTH / ROW_HEIGHT];
402
403 // Pin to control data Vs command sending through SPI
405 };
406}
407
408#endif /* LC5110_HH */
Drawing Context passed to display devices low-level primitives set_pixel() and write_char().
Definition: display.h:248
SPI device driver for Nokia 5110 display chip.
Definition: lcd5110.h:117
void reset()
Reset PCD8544 chip and Nokia 5110 display.
Definition: lcd5110.h:129
void set_temperature_control(TemperatureCoefficient coef)
Set temperature coefficient for Nokia5110 display.
Definition: lcd5110.h:176
void invert()
Invert Nokia5110 LCD display.
Definition: lcd5110.h:226
void full()
Blacken Nokia5110 LCD display.
Definition: lcd5110.h:217
void power_down()
Set Nokia5110 display to power down mode.
Definition: lcd5110.h:188
void normal()
Set Nokia5110 LCD display to normal mode.
Definition: lcd5110.h:236
void blank()
Blank Nokia5110 LCD display.
Definition: lcd5110.h:207
void set_display_bias(uint8_t bias=DEFAULT_BIAS)
Set bias for Nokia5110 LCD display.
Definition: lcd5110.h:143
void power_up()
Set Nokia5110 display to power up mode.
Definition: lcd5110.h:197
void set_display_contrast(uint8_t contrast=DEFAULT_VOP)
Set contrast for Nokia5110 LCD display.
Definition: lcd5110.h:159
static void set()
Set pin level to HIGH (i.e.
Definition: gpio.h:596
static void set_mode(PinMode mode, bool value=false)
Set mode (direction) and value (if output) of DPIN.
Definition: gpio.h:580
uint8_t transfer(uint8_t data)
Transfer one byte to the currently selected SPI slave device through MOSI pin, and get the byte retur...
Definition: spi.h:169
Base class for any SPI slave device.
Definition: spi.h:331
void end_transfer() INLINE
End the current SPI ransfer tot hsi device.
Definition: spi.h:362
#define UNUSED
Specific GCC attribute to declare an argument or variable unused, so that the compiler does not emit ...
Definition: defines.h:45
Generic API to handle any display device (e.g.
Generic API to handle Character Fonts for any display device.
static constexpr uint8_t BV8(uint8_t bit)
Create a uint8_t bitmask for the given bit number.
Definition: bits.h:41
Defines generic API for all display devices.
Definition: display.h:71
TemperatureCoefficient
Possible temperature coeeficient that can be set on Nokia5110 display.
Definition: lcd5110.h:58
@ TC0_1mV_K
TC0 Temperature coefficient 1mV/K
@ TC2_17mV_K
TC0 Temperature coefficient 17mV/K
@ TC1_9mV_K
TC0 Temperature coefficient 9mV/K
@ TC3_24mV_K
TC0 Temperature coefficient 24mV/K
typename FastPinType< DPIN_ >::TYPE FAST_PIN
Useful alias type to the FastPin type matching a given board::DigitalPin.
Definition: gpio.h:694
@ OUTPUT
Digital pin is configured as output.
void delay_us(uint16_t us) INLINE
Delay program execution for the given amount of microseconds.
Definition: time.h:334
Traits for display devices.
Definition: display.h:342
static constexpr uint8_t WIDTH
The width in pixels of DEVICE.
Definition: display.h:360
static constexpr uint8_t HEIGHT
The height in pixels of DEVICE.
Definition: display.h:362