/// <summary> /// Wait for the device to not be busy. /// </summary> /// <param name="microseconds">Time to wait if checking busy state isn't possible/practical.</param> public virtual void WaitForNotBusy(int microseconds) { DelayHelper.DelayMicroseconds((int)(microseconds * WaitMultiplier), allowThreadYield: true); // While we could check for the busy state it isn't currently practical. Most // commands need a maximum of 37μs to complete. Reading the busy flag alone takes // ~200μs (on the Pi) if going through the software driver. Prepping the pins and // reading once can take nearly a millisecond, which clearly is not going to be // performant. // // We might be able to dynamically introduce waits on the busy flag by measuring // the time to take a reading and utilizing the flag if we can check fast enough // relative to the requested wait time. If it takes 20μs to check and the wait time // is over 1000μs we may very well save significant time as the "slow" commands // (home and clear) can finish much faster than the time we've allocated. // Timings in the original HD44780 specification are based on a "typical" 270kHz // clock. (See page 25.) Most instructions take 3 clocks to complete. The internal // clock (fOSC) is documented as varying from 190-350KHz on the HD44780U and 140-450KHz // on the PCF2119x. }
private void WriteBits(byte bits, int count) { int changedCount = 0; for (int i = 0; i < count; i++) { int newBit = (bits >> i) & 1; if (!_useLastByte) { _pinBuffer[changedCount++] = new PinValuePair(_dataPins[i], newBit); } else { // Each bit change takes ~23μs, so only change what we have to // This is particularly impactful when using all 8 data lines. int oldBit = (_lastByte >> i) & 1; if (oldBit != newBit) { _pinBuffer[changedCount++] = new PinValuePair(_dataPins[i], newBit); } } } if (changedCount > 0) { _controller.Write(new ReadOnlySpan <PinValuePair>(_pinBuffer, 0, changedCount)); } _useLastByte = true; _lastByte = bits; // Enable pin needs to be high for at least 450ns when running on 3V // and 230ns on 5V. (PWeh on page 49/52 and Figure 25 on page 58) _controller.Write(_enablePin, PinValue.High); DelayHelper.DelayMicroseconds(1, allowThreadYield: false); _controller.Write(_enablePin, PinValue.Low); }
private void Initialize() { // Prep the pins _controller.OpenPin(_rsPin, PinMode.Output); if (_rwPin != -1) { _controller.OpenPin(_rwPin, PinMode.Output); // Set to write. Once we enable reading have reading pull high and reset // after reading to give maximum performance to write (i.e. assume that // the pin is low when writing). _controller.Write(_rwPin, PinValue.Low); } if (_backlight != -1) { _controller.OpenPin(_backlight, PinMode.Output); if (_backlightBrightness > 0) { // Turn on the backlight _controller.Write(_backlight, PinValue.High); } } _controller.OpenPin(_enablePin, PinMode.Output); for (int i = 0; i < _dataPins.Length; ++i) { _controller.OpenPin(_dataPins[i], PinMode.Output); } // The HD44780 self-initializes when power is turned on to the following settings: // // - 8 bit, 1 line, 5x7 font // - Display, cursor, and blink off // - Increment with no shift // // It is possible that the initialization will fail if the power is not provided // within specific tolerances. As such, we'll always perform the software based // initialization as described on pages 45/46 of the HD44780 data sheet. We give // a little extra time to the required waits as described. if (_dataPins.Length == 8) { // Init to 8 bit mode (this is the default, but other drivers // may set the controller to 4 bit mode, so reset to be safe.) DelayHelper.DelayMilliseconds(50, allowThreadYield: true); WriteBits(0b0011_0000, 8); DelayHelper.DelayMilliseconds(5, allowThreadYield: true); WriteBits(0b0011_0000, 8); DelayHelper.DelayMicroseconds(100, allowThreadYield: true); WriteBits(0b0011_0000, 8); } else { // Init to 4 bit mode, setting _rspin to low as we're writing 4 bits directly. // (Send writes the whole byte in two 4bit/nybble chunks) _controller.Write(_rsPin, PinValue.Low); DelayHelper.DelayMilliseconds(50, allowThreadYield: true); WriteBits(0b0011, 4); DelayHelper.DelayMilliseconds(5, allowThreadYield: true); WriteBits(0b0011, 4); DelayHelper.DelayMicroseconds(100, allowThreadYield: true); WriteBits(0b0011, 4); WriteBits(0b0010, 4); } // The busy flag can NOT be checked until this point. }