Example #1
0
        /// <summary>
        /// Calculates the prescale value from the frequency (according to <see cref="ClockSpeed"/>)
        /// then writes that register, then calls <see cref="ReadFrequency"/> to update properties.
        /// Note the actual frequency may differ to the requested frequency due to clock scale (rounding).
        /// </summary>
        /// <remarks>
        /// The prescale can only be set during sleep mode. This method enters <see cref="Sleep"/> if necessary,
        /// then only if the device was awake before, calls <see cref="Wake"/> afterwards. It's important not to
        /// start output unexpectedly to avoid damage, i.e. if the device was sleeping before, the frequency is
        /// changed without starting the oscillator.
        /// </remarks>
        /// <param name="frequency">Desired frequency to set in Hz.</param>
        /// <returns>
        /// Effective frequency in Hz, read-back and recalculated after setting the desired frequency.
        /// Frequency in Hz. Related properties are also updated.
        /// </returns>
        /// <exception cref="ArgumentOutOfRangeException">
        /// Thrown when <paramref name="frequency"/> is less than <see cref="FrequencyMinimum"/> or greater than
        /// <see cref="FrequencyMaximum"/>.
        /// </exception>
        public int WriteFrequency(int frequency)
        {
            // Validate
            if (frequency < FrequencyMinimum || frequency > FrequencyMaximum)
            {
                throw new ArgumentOutOfRangeException(nameof(frequency));
            }

            // Calculate prescale
            var prescale = CalculatePrescale(frequency, ClockSpeed);

            // Enter sleep mode and record wake status
            var wasAwake = Sleep();

            // Write prescale
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.Prescale, prescale);

            // Read result
            var actual = ReadFrequency();

            // Wake-up if previously running
            if (wasAwake)
            {
                Wake();
            }

            // Update related properties
            PwmMsMinimum = Pca9685ChannelValue.CalculateWidthMs(frequency, 0);
            PwmMsMaximum = Pca9685ChannelValue.CalculateWidthMs(frequency, Pca9685ChannelValue.Maximum);

            // Return actual frequency
            return(actual);
        }
Example #2
0
        /// <summary>
        /// Executes the <see cref="Ms5611Command.ConvertD2Temperature"/> command to measure
        /// pressure at the specified OSR, waits then returns the result.
        /// </summary>
        public int ConvertTemperature(Ms5611Osr rate)
        {
            // Send command to hardware
            I2cExtensions.WriteJoinByte(_hardware, (byte)(Ms5611Command.ConvertD2Temperature + (byte)rate), 0);

            // Wait for completion
            WaitForConversion(rate);

            // Return result
            var result = I2cExtensions.WriteReadBytes(_hardware, (byte)Ms5611Command.AdcRead, 3);

            return(result[0] << 16 | result[1] << 8 | result[2]);
        }
Example #3
0
        /// <summary>
        /// Clears all channels cleanly, then updates all <see cref="Channels"/>.
        /// </summary>
        /// <remarks>
        /// To "cleanly" clear the channels, it is necessary to first ensure they are not disabled,
        /// set them to zero, then disable them. Otherwise the ON value and the low OFF value
        /// remain because writes are ignored when the OFF channel bit 12 is already set.
        /// </remarks>
        public void Clear()
        {
            // Enable all channels
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.AllChannelsOffHigh, 0x00);

            // Zero all channels
            I2cExtensions.WriteJoinBytes(_hardware, (byte)Pca9685Register.AllChannelsOnLow, new byte[] { 0x00, 0x00, 0x00, 0x00 });

            // Disable all channels
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.AllChannelsOffHigh, 0x10);

            // Update channels
            ReadAllChannels();
        }
Example #4
0
        /// <summary>
        /// Writes a single byte at the specified address.
        /// </summary>
        public void WriteByte(int address, byte data)
        {
            // Validate
            if (address < 0 || address > Size - 1)
            {
                throw new ArgumentOutOfRangeException(nameof(address));
            }

            // Get correct I2C device and data for memory address and flags
            var device       = GetI2cDeviceForMemoryAddress(address);
            var addressBytes = GetMemoryAddressBytes(address);

            // Write data
            I2cExtensions.WriteJoinByte(device, addressBytes, data);
        }
Example #5
0
        /// <summary>
        /// Resets the device, updates PROM data and clears current measurements.
        /// </summary>
        public void Reset()
        {
            // Send reset command
            I2cExtensions.WriteJoinByte(_hardware, (byte)Ms5611Command.Reset, 0);

            // Wait for completion
            Task.Delay(TimeSpanExtensions.FromMicroseconds(ResetTime)).Wait();

            // Update PROM values
            ReadProm();

            // Clear measurements
            Pressure    = 0;
            Temperature = 0;
        }
Example #6
0
        /// <summary>
        /// Restarts the device with additional options specified, then updates all properties.
        /// </summary>
        /// <param name="options">
        /// Optional mode 1 parameters to add to the final restart sequence. A logical OR is applied to this value and
        /// the standard <see cref="Pca9685Mode1Bits.Restart"/>, <see cref="Pca9685Mode1Bits.ExternalClock"/> and
        /// <see cref="Pca9685Mode1Bits.AutoIncrement"/> bits.
        /// </param>
        public void Restart(Pca9685Mode1Bits options)
        {
            // Configure according to external clock presence
            var externalClock = ClockIsExternal;
            var delay         = TimeSpan.FromTicks(Convert.ToInt64(Math.Round(TimeSpan.TicksPerMillisecond * 0.5)));

            // Send I2C restart sequence...

            // Write first sleep
            var sleep = (byte)Pca9685Mode1Bits.Sleep;

            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.Mode1, sleep);

            // Write sleep again with external clock option (when present)
            if (externalClock)
            {
                sleep |= (byte)(Pca9685Mode1Bits.ExternalClock);
                I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.Mode1, sleep);
            }
            else
            {
                // At least 500 nanoseconds sleep required using internal clock
                Task.Delay(delay).Wait();
            }

            // Write reset with external clock option and any additional options
            var restart = (byte)(Pca9685Mode1Bits.Restart | Pca9685Mode1Bits.AutoIncrement);

            if (externalClock)
            {
                restart |= (byte)Pca9685Mode1Bits.ExternalClock;
            }
            restart |= (byte)options;
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.Mode1, restart);

            // At least 500 nanoseconds delay to allow oscillator to start
            Task.Delay(delay).Wait();

            // Update all properties
            ReadAll();
        }
Example #7
0
        public Pca9685Device(int busNumber, byte chipNumber, int?clockSpeed,
                             I2cBusSpeed speed = I2cBusSpeed.FastMode, I2cSharingMode sharingMode = I2cSharingMode.Exclusive)
        {
            // Validate
            if (clockSpeed.HasValue && (clockSpeed == 0 || clockSpeed.Value > ClockSpeedMaximum))
            {
                throw new ArgumentOutOfRangeException(nameof(clockSpeed));
            }

            // Get address
            var address = GetI2cAddress(chipNumber);

            // Connect to hardware
            _hardware = I2cExtensions.Connect(busNumber, address, speed, sharingMode);

            // Initialize configuration
            ClockIsExternal  = clockSpeed.HasValue;
            ClockSpeed       = clockSpeed ?? InternalClockSpeed;
            FrequencyDefault = CalculateFrequency(PrescaleDefault, ClockSpeed);
            FrequencyMinimum = CalculateFrequency(PrescaleMaximum, ClockSpeed); // Inverse relationship (max = min)
            FrequencyMaximum = CalculateFrequency(PrescaleMinimum, ClockSpeed); // Inverse relationship (min = max)

            // Build channels
            _channels = new Collection <Pca9685ChannelValue>();
            Channels  = new ReadOnlyCollection <Pca9685ChannelValue>(_channels);
            for (var index = 0; index < ChannelCount; index++)
            {
                _channels.Add(new Pca9685ChannelValue(index));
            }

            // Set "all call" address
            I2cExtensions.WriteJoinByte(_hardware, (byte)Pca9685Register.AllCall, I2cAllCallAddress);

            // Enable auto-increment and "all call"
            I2cExtensions.WriteReadWriteBit(_hardware, (byte)Pca9685Register.Mode1,
                                            (byte)(Pca9685Mode1Bits.AutoIncrement | Pca9685Mode1Bits.AllCall), true);

            // Read current values and update properties
            ReadAll();
        }