Exemplo n.º 1
0
        /// <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.
            }