DUDS
Distributed Update of Data from Something
ST7920.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of the DUDS project. It is subject to the BSD-style
3  * license terms in the LICENSE file found in the top-level directory of this
4  * distribution and at https://github.com/jjackowski/duds/blob/master/LICENSE.
5  * No part of DUDS, including this file, may be copied, modified, propagated,
6  * or distributed except according to the terms contained in the LICENSE file.
7  *
8  * Copyright (C) 2018 Jeff Jackowski
9  */
10 
15 #include <thread>
16 
17 namespace duds { namespace hardware { namespace devices { namespace displays {
18 
19 ST7920::ST7920() : outcfg(5) { }
20 
24  unsigned int w,
25  unsigned int h,
26  std::chrono::nanoseconds delay
27 ) :
28  duds::hardware::display::BppGraphicDisplay(
29  duds::ui::graphics::ImageDimensions(w, h)
30  ),
31  outcfg(5),
32  soonestSend(std::chrono::high_resolution_clock::now())
33 {
34  configure(std::move(outPins), std::move(enablePin), w, h, delay);
35 }
36 
38  if (outputs.havePins()) {
39  off();
40  }
41 }
42 
46  unsigned int w,
47  unsigned int h,
48  std::chrono::nanoseconds delay
49 ) {
50  // range check on display size
51  if ((w > 256) || (w < 16) || (h > 64) || (h < 16)) {
55  )
56  );
57  }
58  if (!outPins.havePins() || !enablePin) {
60  }
61  // requires 5 pins: 4 data, 1 control, all output
62  if (outPins.size() != 5) {
64  }
65  // get the capabilities for inspection
66  std::vector<duds::hardware::interface::DigitalPinCap> caps =
67  outPins.capabilities();
68  // iteratate over all the pins
69  std::vector<duds::hardware::interface::DigitalPinCap>::const_iterator iter =
70  caps.cbegin();
71  unsigned int pos = 0;
72  for (; iter != caps.cend(); ++pos, ++iter) {
73  // check for no output ability
74  if (!iter->canOutput()) {
77  duds::hardware::interface::PinErrorId(outPins.globalId(pos))
78  );
79  }
80  // work out the actual output config
82  iter->firstOutputDriveConfigFlags()
83  );
84  }
85  // store this access object; seems good if it got this far without
86  // an exception
87  outputs = std::move(outPins);
88  enable = std::move(enablePin);
89  frmbuf.resize(w, h);
90  nibblePeriod = delay;
91 }
92 
93 
94 void ST7920::wait() const {
95  auto remain = soonestSend - std::chrono::high_resolution_clock::now();
96  if (remain.count() > 0) {
98  }
99 }
100 
102  if (!outputs.havePins()) {
104  }
105  // Wait until the display can take more data. Do this before getting
106  // hardware access so that the hadrware remains availble for other
107  // threads during this initial wait.
108  wait();
109  // request hardware access
110  outputs.access(acc.output);
111  enable.access(acc.enable);
112  // make all pins outputs
114 }
115 
116 void ST7920::sendByte(ST7920::Access &acc, int val) {
117  // write out the text flag as the MSb along with the high-order nibble
118  acc.output.write((val & 0x1F0) >> 4); // 5-bit output
119  // wait
121  // tell LCD to read
122  acc.enable.select();
123  // another wait
125  // LCD should be done reading
126  acc.enable.deselect();
127  // sending a whole byte?
128  if (~val & nibbleFlag) {
129  // write out the low-order nibble; leave command flag alone
130  acc.output.write(val & 0xF, 4); // 4-bit output
131  // wait
133  // tell LCD to read
134  acc.enable.select();
135  // wait again
137  // LCD should be done reading
138  acc.enable.deselect();
139  }
140  // record time when more data can be sent
141  soonestSend = std::chrono::high_resolution_clock::now();
142  if (val < 2) {
143  soonestSend += std::chrono::milliseconds(2);
144  } else {
145  soonestSend += std::chrono::microseconds(78);
146  }
147 }
148 
150  {
151  // LCD intialization commands in reverse order they are sent
152  static const std::uint8_t initdata[] {
153  0x26, // use graphic output; will show frame
154  0x24, // use extended commands
155  0x6, // increment cursor, no display shift
156  0xC, // turn on display w/o cursor
157  0x1, // clear display
158  0x8, // turn off display
159  0x20, // 4 bit bus mode
160  0x30, // 8-bit bus mode; sync nibble reception
161  0x30, // 8-bit bus mode; sync nibble reception
162  0x30 // 8-bit bus mode; sync nibble reception
163  };
164  Access acc;
165  preparePins(acc);
166  acc.output.output(false);
167  acc.enable.select();
168  std::this_thread::sleep_for(std::chrono::milliseconds(4));
169  acc.enable.deselect();
170  int loop = sizeof(initdata) - 1;
171  for (; loop >= sizeof(initdata) - 4; --loop) {
172  sendByte(acc, nibbleFlag | initdata[loop]);
173  std::this_thread::sleep_for(std::chrono::milliseconds(2));
174  }
175  for (; loop >= 0; --loop) {
176  sendByte(acc, initdata[loop]);
177  std::this_thread::sleep_for(std::chrono::milliseconds(2));
178  }
179  }
180  // clear the display; the closest display command for this only clears the
181  // text output buffer
182  frmbuf.setImage();
184  // defeat image change logic
185  img.clearImage();
186  // output a cleared frame; previous frame will be briefly visible
187  outputFrame(&img);
188 }
189 
190 void ST7920::off() {
191  Access acc;
192  preparePins(acc);
193  sendByte(acc, 1); // suspend command
194 }
195 
196 void ST7920::on() {
197  Access acc;
198  preparePins(acc);
199  sendByte(acc, 0x26); // graphic display mode; previously set
200 }
201 
203  ST7920::Access &acc,
204  const std::uint16_t *start,
205  const std::uint16_t *end,
206  int pos
207 ) {
208  // set location
209  wait();
210  sendByte(acc, (pos & 0x3F) | 0x80);
211  wait();
212  sendByte(acc, ((pos >> 8) & 0x3F) | 0x80);
213  do {
214  // BppImage and the display use the opposite ordering of bits
215  std::uint16_t out = duds::general::ReverseBits(*start);
216  // write out the image data
217  wait();
218  sendByte(acc, textFlag | (out >> 8));
219  wait();
220  sendByte(acc, textFlag | (out & 0xFF));
221  } while (start++ != end);
222 }
223 
225  Access acc;
226  preparePins(acc);
227  // width in 16-bit ints
228  int wblk = width() / 16 + (((width() % 16) > 0) ? 1 : 0);
229  // loop through the images
230  for (int h = 0; h < height(); ++h) {
231  // pointers to two-byte ints of image data; display works with 2 bytes
232  std::uint16_t *dpix = (std::uint16_t*)frmbuf.bufferLine(h); // dest
233  const std::uint16_t *spix = (std::uint16_t*)img->bufferLine(h); // src
234  std::uint16_t *cx = nullptr, *lx; // first and last changed X coordinate
235  int spos; // starting location of change
236  for (int w = 0; w < wblk; ++dpix, ++spix, ++w) {
237  // find differences between frame buffer and new image
238  if (*dpix != *spix) {
239  // record new value
240  *dpix = *spix;
241  // no change pending?
242  if (!cx) {
243  // mark this change
244  cx = lx = dpix;
245  spos = w;
246  }
247  // more than 1 spot (two bytes) since last change?
248  else if (lx < (dpix - 1)) {
249  // send pending change
250  writeBlock(acc, cx, lx, h | (spos << 8));
251  // mark new change
252  cx = lx = dpix;
253  spos = w;
254  }
255  // add to pending change
256  else {
257  lx = dpix;
258  }
259  }
260  }
261  // have pending change?
262  if (cx) {
263  // send pending change
264  writeBlock(acc, cx, lx, h | (spos << 8));
265  }
266  }
267 }
268 
269 } } } }
const ImageDimensions & dimensions() const
Returns the dimensions of the image.
Definition: BppImage.hpp:1112
duds::hardware::interface::DigitalPinSetAccess output
The set used for the 4 data pins and the text flag, more commonly referred to as "RS".
Definition: ST7920.hpp:112
boost::error_info< struct Info_ImageDimensions, ImageDimensions > ImageErrorDimensions
Image dimensions relevant to the error.
Definition: BppImage.hpp:293
int height() const
Returns the height of the frame buffer.
void preparePins(Access &acc)
Obtains access to the pins and configures them for output.
Definition: ST7920.cpp:101
An attempt was made to use an uninitialized display object.
void YieldingWait(Duration duration)
Waits for a minumum period of time by calling std::this_thread::yield() in a loop.
void write(Int val, int bits) const
Writes out a number in binary to the pins.
const PixelBlock * bufferLine(int py) const
Returns a pointer to the start of the given line.
Definition: BppImage.cpp:175
Defines the configuration for a digital general purpose I/O pin.
ST7920()
Initializes the object with an invalid display size and no pins to use.
Definition: ST7920.cpp:19
The operation has too few or much data to work on the pins, which can alternately be stated as having...
Definition: PinErrors.hpp:50
void on()
Commands the display to turn on.
Definition: ST7920.cpp:196
duds::hardware::interface::DigitalPinSet outputs
Represents the 5 output lines, other than enable, that are needed to communicate with the LCD...
Definition: ST7920.hpp:52
STL namespace.
duds::hardware::interface::ChipAccess enable
Used to assert the enable line of the LCD.
Definition: ST7920.hpp:116
move_impl move(unsigned int c, unsigned int r)
Display stream manipulator that moves the display cursor to the given location.
A pin required for the operation does not exist or is unavailable to the process. ...
Definition: PinErrors.hpp:70
DigitalPinConfig modifyConfig(unsigned int pos, const DigitalPinConfig &conf) const
Modifies the configuration of a pin.
boost::error_info< struct Info_PinId, unsigned int > PinErrorId
The pin global ID involved in the error.
Definition: PinErrors.hpp:97
Stores the dimensions of an image.
Definition: BppImage.hpp:125
Stores access objects together.
Definition: ST7920.hpp:107
An object to wrap together a ChipSelectManager and chip ID to simplify code that needs to repeatedly ...
Definition: ChipSelect.hpp:24
The specified display size is unsupported, or there is a display size mismatch.
std::chrono::nanoseconds nibblePeriod
The amount of time to allow the display to read data.
Definition: ST7920.hpp:74
void initialize()
Initializes the display for use.
Definition: ST7920.cpp:149
Represents a set of pins on a single DigitalPort.
Flag for sending text to the display rather than a command.
Definition: ST7920.hpp:84
std::unique_ptr< DigitalPinSetAccess > access() const
Obtains an access object for all the pins in this set.
bool havePins() const
Returns true if this object has been given any pins to represent.
Flag to send only a nibble rather than a whole byte; used in display initalization.
Definition: ST7920.hpp:93
void off()
Commands the display to turn off.
Definition: ST7920.cpp:190
void deselect()
Deselects the chip.
Definition: ChipAccess.hpp:69
int width() const
Returns the width of the frame buffer.
std::unique_ptr< ChipAccess > access()
Obtains a ChipAccess object.
Definition: ChipSelect.cpp:32
virtual ~ST7920()
Calls off().
Definition: ST7920.cpp:37
void output(unsigned int pos, bool state) const
Changes the output state of a pin.
void resize(const duds::ui::graphics::ImageDimensions &newdim)
Changes the size of the image.
Definition: BppImage.cpp:123
Indicates that a request to configure a pin to output was made of a pin that cannot output...
virtual void outputFrame(const duds::ui::graphics::BppImage *img)
Writes out only the changed portions of the image to the display, and updates the image in frmbuf to ...
Definition: ST7920.cpp:224
std::chrono::high_resolution_clock::time_point soonestSend
The soonest time a new command can be sent to the display.
Definition: ST7920.hpp:70
void sendByte(Access &acc, int val)
Sends a byte to the display a nibble at a time.
Definition: ST7920.cpp:116
duds::ui::graphics::BppImage frmbuf
The frame buffer.
void clearImage()
Clears every pixel (change to false) in the image.
Definition: BppImage.hpp:1509
General graphics related code.
Definition: HD44780.hpp:15
Integer ReverseBits(Integer i)
Reverses the bits in a given value.
Definition: ReverseBits.hpp:26
void configure(duds::hardware::interface::DigitalPinSet &&outPins, duds::hardware::interface::ChipSelect &&enablePin, unsigned int w, unsigned int h, std::chrono::nanoseconds delay=std::chrono::nanoseconds(8000))
Sets the pins to use for communicating with the display.
Definition: ST7920.cpp:43
BppGraphicDisplay()=default
Construct with an empty frame buffer.
void wait() const
Waits until the time in soonestSend has passed.
Definition: ST7920.cpp:94
void select()
Selects the chip.
Definition: ChipAccess.hpp:63
#define DUDS_THROW_EXCEPTION(x)
Works like BOOST_THROW_EXCEPTION, but includes a stack trace if DUDS_ERRORS_VERBOSE is defined...
Definition: Errors.hpp:48
An image that uses a single bit to represent the state of each pixel; a black or white picture...
Definition: BppImage.hpp:321
void setImage()
Sets every pixel (set to true) in the image.
Definition: BppImage.hpp:1515
void writeBlock(ST7920::Access &acc, const std::uint16_t *start, const std::uint16_t *end, int pos)
Writes a contiguous block of pixel data to the display after setting the next location to write...
Definition: ST7920.cpp:202
std::vector< duds::hardware::interface::DigitalPinConfig > outcfg
The best output configuration for the display bus given the port in use.
Definition: ST7920.hpp:64
duds::hardware::interface::ChipSelect enable
Used to represent the enable line of the LCD.
Definition: ST7920.hpp:60