/// <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); }
/// <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]); }
/// <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(); }
/// <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); }
/// <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; }
/// <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(); }
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(); }