/// <summary> /// Reads the PWM "off" (falling) value of a channel, and updates it in <see cref="Channels"/>. /// </summary> /// <param name="index">Zero based channel number (0-15).</param> /// <returns>Channel value.</returns> public int ReadChannelOff(int index) { // Validate if (index < 0 | index >= ChannelCount) { throw new ArgumentOutOfRangeException(nameof(index)); } // Calculate register address of second word value var register = (byte)(GetChannelAddress(index) + sizeof(ushort)); // Read and convert value var bytes = I2cExtensions.WriteReadBytes(_hardware, register, sizeof(ushort)); var value = BitConverter.ToUInt16(bytes, 0); // Update channel when changed var oldValue = _channels[index]; if (oldValue.Off != value) { _channels[index] = new Pca9685ChannelValue(oldValue.On, value); } // Return result return(value); }
/// <summary> /// Writes the "on" and "off" values of a channel together, and updates it in <see cref="Channels"/>. /// </summary> /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param> /// <param name="value"><see cref="Pca9685ChannelValue"/> to write.</param> /// <returns> /// Updated channel value or null when all channels were updated. /// </returns> public Pca9685ChannelValue?WriteChannel(int index, Pca9685ChannelValue value) { // Validate if (index <0 | index> ChannelCount) { throw new ArgumentOutOfRangeException(nameof(index)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } // Calculate register address var register = GetChannelAddress(index); // Convert and write value var bytes = value.ToByteArray(); I2cExtensions.WriteJoinBytes(_hardware, register, bytes); // Read and return result when single channel if (index < ChannelCount) { return(ReadChannel(index)); } // Read all channels when "all call". ReadAllChannels(); return(null); }
/// <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> /// Reads a single byte at the "current address" (next byte after the last operation). /// </summary> public byte[] ReadPage(int length) { // Validate if (length < 0 || length > Size) { throw new ArgumentOutOfRangeException(nameof(length)); } // Get correct I2C device for memory address and flags var device = GetI2cDeviceForMemoryAddress(0); // Read data with chunking when transfer size exceeds limit var resultBuffer = new byte[length]; var remaining = length; var offset = 0; do { // Check transfer size and reduce when necessary var transferSize = remaining; if (transferSize > I2cExtensions.MaximumTransferSize) { transferSize = I2cExtensions.MaximumTransferSize; } // Read data var buffer = I2cExtensions.ReadBytes(device, transferSize); Array.ConstrainedCopy(buffer, 0, resultBuffer, offset, transferSize); // Next transfer when necessary... remaining -= transferSize; offset += transferSize; }while (remaining > 0); return(resultBuffer); }
/// <summary> /// Reads a single byte at the "current address" (next byte after the last operation). /// </summary> public byte ReadByte() { // Get correct I2C device for memory address and flags var device = GetI2cDeviceForMemoryAddress(0); // Read and return data return(I2cExtensions.ReadByte(device)); }
public Mb85rc256vDevice(int busNumber, byte chipNumber, I2cBusSpeed speed = I2cBusSpeed.FastMode, I2cSharingMode sharingMode = I2cSharingMode.Exclusive) : base(chipNumber, MemorySize) { // Get address var address = GetDataI2cAddress(chipNumber); // Connect to hardware Hardware = I2cExtensions.Connect(busNumber, address, speed, sharingMode); }
/// <summary> /// Reads all channels and updates <see cref="Channels"/>. /// </summary> public void ReadAllChannels() { // Read all channels as one block of data var data = I2cExtensions.WriteReadBytes(_hardware, ChannelStartAddress, ChannelSize * ChannelCount); // Update properties for (var index = 0; index < ChannelCount; index++) { _channels[index] = Pca9685ChannelValue.FromByteArray(data, ChannelSize * index); } }
/// <summary> /// Reads the current value of the <see cref="Pca9685Register.Mode2"/> register. /// </summary> /// <returns>Bit flags corresponding to the actual mode byte.</returns> public Pca9685Mode2Bits ReadMode2() { // Read register var value = (Pca9685Mode2Bits)I2cExtensions.WriteReadByte(_hardware, (byte)Pca9685Register.Mode2); // Update property Mode2Register = value; // Return result return(value); }
/// <summary> /// Reads a coefficient value from the PROM. /// </summary> /// <param name="index">Coefficient index (0-7).</param> /// <param name="buffer">Target buffer.</param> /// <param name="offset">Target offset.</param> /// <remarks> /// Reads <see cref="Ms5611PromData.CoefficientSize"/> bytes into the target buffer at the specified offset. /// </remarks> private void ReadPromCoefficient(int index, byte[] buffer, int offset) { // Calculate address var coefficientOffset = (byte)(index * Ms5611PromData.CoefficientSize); var address = (byte)(Ms5611Command.PromRead + coefficientOffset); // Read from hardware return value var coefficient = I2cExtensions.WriteReadBytes(_hardware, address, Ms5611PromData.CoefficientSize); Array.ConstrainedCopy(coefficient, 0, buffer, offset, Ms5611PromData.CoefficientSize); }
/// <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> /// 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> /// Reads a single byte "randomly" at the specified address. /// </summary> public byte ReadByte(int address) { // 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); // Read and return data return(I2cExtensions.WriteReadByte(device, addressBytes)); }
/// <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> /// Writes the PWM "on" (rising) value of a channel. /// </summary> /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param> /// <param name="value">12-bit channel value in the range 0-<see cref="Pca9685ChannelValue.Maximum"/>.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="value"/> is greater than <see cref="Pca9685ChannelValue.Maximum"/>.</exception> public void WriteChannelOn(int index, int value) { // Validate if (value > Pca9685ChannelValue.Maximum) { throw new ArgumentOutOfRangeException(nameof(value)); } // Calculate register address var register = GetChannelAddress(index); // Convert and write value var data = BitConverter.GetBytes(value); I2cExtensions.WriteJoinBytes(_hardware, register, data); }
/// <summary> /// Reads the prescale register and calculates the <see cref="Frequency"/> (and related properties) /// based on <see cref="ClockSpeed"/>. /// </summary> /// <returns> /// Frequency in Hz. Related properties are also updated. /// </returns> public int ReadFrequency() { // Read prescale register var prescale = I2cExtensions.WriteReadByte(_hardware, (byte)Pca9685Register.Prescale); // Calculate frequency var frequency = CalculateFrequency(prescale, ClockSpeed); // Update related properties Frequency = frequency; PwmMsMinimum = Pca9685ChannelValue.CalculateWidthMs(frequency, 0); PwmMsMaximum = Pca9685ChannelValue.CalculateWidthMs(frequency, Pca9685ChannelValue.Maximum); // Return result return(frequency); }
/// <summary> /// Writes the PWM "off" (falling) value of a channel. /// </summary> /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param> /// <param name="value">12-bit channel value in the range 0-<see cref="Pca9685ChannelValue.Maximum"/>.</param> /// <exception cref="ArgumentOutOfRangeException">Thrown when the <paramref name="value"/> is greater then <see cref="Pca9685ChannelValue.Maximum"/>.</exception> public void WriteChannelOff(int index, int value) { // Validate if (value > Pca9685ChannelValue.Maximum) { throw new ArgumentOutOfRangeException(nameof(value)); } // Calculate register address of second word value var register = (byte)(GetChannelAddress(index) + sizeof(ushort)); // Convert and write value var bytes = BitConverter.GetBytes(value); I2cExtensions.WriteJoinBytes(_hardware, register, bytes); }
public Ms5611Device(int busNumber, bool csb, Ms5611Osr rate, I2cBusSpeed speed = I2cBusSpeed.FastMode, I2cSharingMode sharingMode = I2cSharingMode.Exclusive) { // Get address ChipSelectBit = csb; Address = GetI2cAddress(csb); // Connect to hardware _hardware = I2cExtensions.Connect(busNumber, Address, speed, sharingMode); // Initialize members Prom = new Ms5611PromData(); Osr = rate; // Read current calibration data (potentially not stable until next reset) // We don't reset automatically so that it is possible for any ongoing tasks to complete ReadProm(); }
/// <summary> /// Reads a whole channel value (on and off), and updates it in <see cref="Channels"/>. /// </summary> /// <param name="index">Zero based channel number (0-15).</param> /// <returns>Channel value</returns> public Pca9685ChannelValue ReadChannel(int index) { // Validate if (index < 0 | index >= ChannelCount) { throw new ArgumentOutOfRangeException(nameof(index)); } // Calculate register address var register = GetChannelAddress(index); // Read value var bytes = I2cExtensions.WriteReadBytes(_hardware, register, sizeof(ushort) * 2); // Update channel property and return result var value = Pca9685ChannelValue.FromByteArray(bytes); return(_channels[index] = value); }
/// <summary> /// Writes multiple channels together (both "on" and "off" values), and updates it in <see cref="Channels"/>. /// </summary> /// <param name="index">Zero based channel number (0-15) or 16 for the "all call" channel.</param> /// <param name="values">Collection of <see cref="Pca9685ChannelValue"/>s to write.</param> public void WriteChannels(int index, IList <Pca9685ChannelValue> values) { // Validate if (index <0 | index> ChannelCount) { throw new ArgumentOutOfRangeException(nameof(index)); } if (values == null || values.Count == 0) { throw new ArgumentNullException(nameof(values)); } var count = values.Count; if (index + count > ChannelCount) { throw new ArgumentOutOfRangeException(nameof(values)); } // Build I2C packet var data = new byte[1 + ChannelSize * count]; // Calculate first register address var register = GetChannelAddress(index); data[0] = register; // Write channels and update properties for (int dataIndex = 0, dataOffset = 1; dataIndex < count; dataIndex++, dataOffset += ChannelSize) { // Get channel data var channelData = values[dataIndex].ToByteArray(); // Copy to buffer Array.ConstrainedCopy(channelData, 0, data, dataOffset, ChannelSize); // Update property _channels[index + dataIndex] = Pca9685ChannelValue.FromByteArray(channelData); } // Send packet I2cExtensions.WriteBytes(_hardware, data); }
public static Mb85rcvDeviceId?GetDeviceId(int busNumber, byte idAddress, byte dataAddress, I2cBusSpeed speed = I2cBusSpeed.FastMode, I2cSharingMode sharingMode = I2cSharingMode.Exclusive) { // Connect to ID device using (var framIdRegister = I2cExtensions.Connect(busNumber, idAddress, speed, sharingMode)) { // Send ID command sequence, returning device ID bytes var dataAddress8bit = (byte)(dataAddress << 1); var data = new byte[Mb85rcvDeviceId.Size]; var transfer = framIdRegister.WriteReadPartial(new[] { dataAddress8bit }, data); if (transfer.Status == I2cTransferStatus.SlaveAddressNotAcknowledged) // Any other error must throw { // Return null when not found return(null); } // Decode and return ID when found return(new Mb85rcvDeviceId(data)); } }
/// <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(); }
/// <summary> /// Leaves sleep mode. /// </summary> /// <remarks> /// Clears the <see cref="Pca9685Register.Mode1"/> register <see cref="Pca9685Mode1Bits.Sleep"/> bit /// then waits for <see cref="ModeSwitchDelay"/> to allow the oscillator to start. /// </remarks> /// <returns> /// True when mode was changed, false when not sleeping. /// </returns> public bool Wake() { // Read sleep bit (do nothing when already sleeping) var sleeping = I2cExtensions.WriteReadBit(_hardware, (byte)Pca9685Register.Mode1, (byte)Pca9685Mode1Bits.Sleep); if (!sleeping) { return(false); } // Clear sleep bit I2cExtensions.WriteReadWriteBit(_hardware, (byte)Pca9685Register.Mode1, (byte)Pca9685Mode1Bits.Sleep, false); // Wait for completion Task.Delay(ModeSwitchDelay).Wait(); // Update related properties ReadMode1(); // Return changed return(true); }
public Mb85rc04vDevice(int busNumber, byte chipNumber, I2cBusSpeed speed = I2cBusSpeed.FastMode, I2cSharingMode sharingMode = I2cSharingMode.Exclusive) : base(chipNumber, MemorySize) { // Check device addresses var lowerAddress = GetDataI2cAddress(chipNumber, false); var upperAddress = GetDataI2cAddress(chipNumber, true); // Connect to devices try { Hardware = I2cExtensions.Connect(busNumber, lowerAddress, speed, sharingMode); HardwareUpper = I2cExtensions.Connect(busNumber, upperAddress, speed, sharingMode); } catch { // Free resources on initialization error Hardware?.Dispose(); HardwareUpper?.Dispose(); // Continue error throw; } }
/// <summary> /// Reads multiple channel values (both on and off for each), and updates it in <see cref="Channels"/>. /// </summary> /// <param name="index">Zero based channel number (0-15).</param> /// <param name="count">Number of channels to read.</param> /// <returns>Channel values</returns> public Collection <Pca9685ChannelValue> ReadChannels(int index, int count) { // Validate if (index < 0 | index >= ChannelCount) { throw new ArgumentOutOfRangeException(nameof(index)); } if (count < 1 || index + count > ChannelCount) { throw new ArgumentOutOfRangeException(nameof(count)); } // Calculate register address var register = GetChannelAddress(index); // Send I2C command to read channels in one operation var data = I2cExtensions.WriteReadBytes(_hardware, register, ChannelSize * count); // Update channel properties and add to results var results = new Collection <Pca9685ChannelValue>(); for (int channelIndex = index, offset = 0; count > 0; count--, channelIndex++, offset += ChannelSize) { // Calculate value var value = Pca9685ChannelValue.FromByteArray(data, offset); // Update property _channels[channelIndex] = value; // Add to results results.Add(value); } // Return results return(results); }