PyHSL Reference#

I2CDevice methods#

constructor#

Create a new I2CDevice object.

I2CDevice(address, offset_width, data_width, name, auto_retry=False, ten_bit_address=False, no_virtual_address=False)

where:

  • address is the device’s I2C address.

  • offset_width is the number of bits used to specify an offset for this device. Currently, this must be either 8 or 16.

  • data_width is the number of bits in a register for this device. Currently, this must be either 8 or 16.

  • name is a name for this device (used primarily for logging and error reporting).

  • auto_retry tells the system that failed I2C operations should always be retried.

  • ten_bit_address tells the system that this device uses 10-bit addressing. (7-bit addressing is the default.)

  • no_virtual_address tells the system that the physical address for this device should always be used. By default, the virtual address assigned to this device (if any) will be used instead.

poll#

Poll an I2C register until its value reaches an expected value or the poll times out. If the poll times out, fail the entire HSL sequence.

poll(offset, expectedValue, mask, intervalInUsec, retries)

where:

  • offset is the offset of the register being polled.

  • expectedValue is the expected value of the register.

  • mask is the bitmask to apply for the check.

  • intervalInUsec is the interval between retries.

  • retries is the number of times to retry the check.

The operation is equivalent to this:

while retries >= 0:
  registerValue = i2cReadRegister(offset)
  # Note that an I2C NACK is treated as if the read did not match, and does not immediately fail the operation.
  if i2cReadDidNotNack() && ((registerValue & mask) == expectedValue):
    return
  retries -= 1
  if retries >= 0:
    delay(intervalInUsec)

fail_sequence()

readDiscard#

Read an I2C register and discard the result.

readDiscard(offset)

where:

  • offset is the offset of the register being read.

This method is typically used only when the purpose of the read is to induce a side effect. It has the same effect as calling readVerify(offset, 0, 0).

readToMemory#

Read bytes from I2C into a memory block.

readToMemory(i2cOffset, memoryBlock.fieldName)

where:

  • i2cOffset is the offset of the first byte to read from the I2C device.

  • memoryBlock is the MemoryBlock object in which to store the bytes.

  • fieldName is the field in the memoryBlock’s associated layout that specifies the offset and size of the values in memory.

The operation is equivalent to this:

size = memoryBlock.fieldName.size
memoryOffset = memoryBlock.fieldName.offset
for i in range(size):
  registerValue = i2cReadByte(i2cOffset + i)
  memoryBlock[memoryOffset + i] = registerValue

readVerify#

Read an I2C register and verify that its value is equal to the expected value. If it is not equal, fail the entire HSL sequence.

readVerify(offset, expectedValue, mask)

where:

  • offset is the offset of the register being read.

  • expectedValue is the expected value of the register.

  • mask is the bitmask to apply for the check.

The operation is equivalent to this:

registerValue = i2cReadRegister(offset)
if (registerValue & mask) != expectedValue:
  fail_sequence()

readVerifyFromMemory#

Read an I2C register and verify that its value is equal to the expected value, which comes from a memory block. If it is not equal, fail the entire HSL sequence.

readVerifyFromMemory(i2cOffset, memoryBlock, memoryOffset, mask=maskValue)

where:

  • i2cOffset is the offset of the register being read.

  • memoryBlock is the MemoryBlock object that contains the expected value.

  • memoryOffset is the offset within memoryBlock of the expected value.

  • mask (optional) is the bitmask to apply for the check. This parameter must be specified as a named parameter (for example, mask=0xF0F0) instead of a positional parameter (simply 0xF0F0).

The operation is equivalent to this:

registerValue = i2cReadRegister(i2cOffset)
expectedValue = memoryBlock[memoryOffset]  # size is this device's data width (1 or 2 bytes)
if (registerValue & mask) != expectedValue:
  fail_sequence()

If memoryBlock has an associated MemoryLayout, the alternate form may be used:

readVerifyFromMemory(i2cOffset, memoryBlock.fieldName, mask=maskValue)

where:

  • memoryBlock.fieldName is the location of the expected value. fieldName must be the name of a field in the associated MemoryLayout. That field’s size must be equal to this device’s data width (1 or 2 bytes).

readVerifyStream#

Read a series of bytes from I2C and verify that they are equal to the array of expected byte values. If any are not equal, fail the entire HSL sequence.

readVerifyStream(i2cOffset, expectedValuesList)

where:

  • i2cOffset is the offset of the first byte read from the device.

  • expectedValuesList is a Python sequence (list or tuple) containing byte values.

The operation is equivalent to this:

for i in range(len(expectedValuesList)):
  registerValue = i2cReadByte(i2cOffset + i)
  if registerValue != expectedValuesList[i]:
    fail_sequence()

readVerifyStreamFromMemory#

Read a series of bytes from I2C and verify that they are equal to an array of expected byte values in memory. If any are not equal, fail the entire HSL sequence.

readVerifyStreamFromMemory(i2cOffset, memoryBlock, memoryOffset, size)

where:

  • i2cOffset is the offset of the first byte read from the device.

  • memoryBlock is the MemoryBlock object that contains the expected values.

  • memoryOffset is the offset within memoryBlock of the first expected value.

  • size is the number of bytes to read and compare.

The operation is equivalent to this:

for i in range(size):
  registerValue = i2cReadByte(i2cOffset + i)
  expectedValue = memoryBlock[memoryOffset + i]
  if registerValue != expectedValue:
    fail_sequence()

If memoryBlock has an associated MemoryLayout, the alternate form may be used:

readVerifyStreamFromMemory(i2cOffset, memoryBlock.fieldName)

where:

  • memoryBlock.fieldName is the location of the expected values. fieldName must be the name of a field in the associated MemoryLayout. In this case, the number of bytes read and compared will be the size of the fieldName field.

write#

Write values to I2C. This method has a number of alternative parameter lists, described in the following subsections.

write(i2cOffset, data)#

Write 1 or 2 bytes of data to the device at the specified i2cOffset. If the data_width specified at device creation was 8, one byte will be written; if it was 16, two bytes will be written.

write(((off1, data1), (off2, data2), …))#

Write a series of registers in the device. This is equivalent to:

  • write(off1, data1)

  • write(off2, data2)

  • and so on

write(i2cOffset, (byte0, byte1, …))#

Write all bytes in the second parameter to the device, in order, beginning at the specified i2cOffset. This is the “streaming” version of write().

writeMasked#

Write a masked subset of the bits in an I2C register. This operation performs a read-modify-write.

writeMasked(i2cOffset, data, mask)

where:

  • i2cOffset is the offset of the register being modified.

  • data is the value being written.

  • mask specifies the bits in the register to modify.

The operation is equivalent to this:

oldValue = i2cReadRegister(i2cOffset)
newValue = (data & mask) | (oldValue & ~mask)
i2cWriteRegister(i2cOffset, newValue)

writeFromMemory#

Write bytes from a memory block to I2C.

writeFromMemory(i2cOffset, memoryBlock.fieldName)

where:

  • i2cOffset is the offset of the first byte to write to the I2C device.

  • memoryBlock is the MemoryBlock object from which to load the bytes.

  • fieldName is the field in the memoryBlock’s associated layout that specifies the offset and size of the values in memory.

The operation is equivalent to this:

size = memoryBlock.fieldName.size
memoryOffset = memoryBlock.fieldName.offset
for i in range(size):
  registerValue = memoryBlock[memoryOffset + i]
  i2cWriteByte(i2cOffset + i, registerValue)

GPIOPin methods#

constructor#

Create a new GPIOPin object.

GPIOPin(address, name, readable=True, writable=True)

where:

  • address is the address of the pin. The meaning of this is platform-specific.

  • name is a name for this pin (used primarily for logging and error reporting).

  • readable specifies whether this pin can be read by Tegra.

  • writable specifies whether this pin can be written by Tegra.

poll#

Poll the pin until its value reaches an expected value or the poll times out. If the poll times out, fail the entire HSL sequence.

poll(expectedValue, intervalInUsec, retries)

where:

  • expectedValue is the expected value of the pin. True (or any other “true” value) means HIGH; False (or any other “false” value) means LOW.

  • intervalInUsec is the interval between retries.

  • retries is the number of times to retry the check.

This operation will fail if the pin was constructed with readable = False.

readVerify#

Read the pin and verify that its value is equal to the expected value. If it is not equal, fail the entire HSL sequence.

readVerify(expectedValue)

where:

  • expectedValue is the expected value of the pin.

This operation will fail if the pin was constructed with readable = False.

write#

Write the pin with the specified value.

write(value)

where:

  • value is the value to write to the pin. True (or any other “true” value) means HIGH; False (or any other “false” value) means LOW.

This operation will fail if the pin was constructed with writable = False.

MemoryLayout methods#

constructor#

Create a new MemoryLayout object.

MemoryLayout(name)

where:

  • name is the name of this layout object. It must be unique within this PyHSL invocation.

addItem#

Add a field to the memory layout. Each field reserves a number of bytes in the layout, beginning at byte 0 for the first field.

addItem(name, size, description, defaults)

where:

  • name is the name of this field. It must be unique within this layout.

  • size is the number of bytes taken by this field.

  • description (optional) is a textual description of this field.

  • defaults (optional) is a Python bytes object that provides default values for all bytes in the field. This does not affect runtime HSL operation, but can be used by developer tools.

MemoryBlock methods#

constructor#

Create a new MemoryBlock object.

MemoryBlock(Layout, name)

where:

  • layout is the MemoryLayout object associated with this memory block. If provided, this allows instructions that use this memory block to refer to a field in the layout, rather than manually specifying an offset and size.

  • name is the name of this memory block. It must be unique among all memory block names in this source file.

Sequence methods#

constructor#

Create a new Sequence object.

Sequence(name, max_blob_size, devices, gpios, fences, blocks)

where:

  • name is the name of this sequence. It must be unique among all sequence names in this source file.

  • max_blob_size (optional) is the maximum number of bytes of the HSL bytecode generated for this sequence. It defaults to 0x10000.

  • devices (optional) is a list of I2CDevices that should be included in the device table. It defaults to None, which sets all the known I2CDevices. An empty list represents no devices.

  • gpios (optional) is a list of GPIOPins that should be included in the gpio table. It defaults to None, which sets all the known GPIOPins. An empty list represents no gpio pins.

  • fences (optional) is a list of Fences that should be included in the fence table. It defaults to None, which sets all the known Fences. An empty list represents no fences.

  • blocks (optional) is a list of MemoryBlocks that should be included in the memory block table. It defaults to None, which sets all the known MemoryBlocks. An empty list represents no memory blocks.

Note that the devices, gpios, fences, and blocks parameters are generally no longer needed. Earlier versions of PyHSL would by default include every I2C device, GPIO pin, and so on that had been defined, regardless of whether they were used in the Sequence. With newer versions, only the objects actually used in the Sequence will be included in their respective tables.

annotate#

Insert an annotation into the HSL stream. An annotation is simply a comment; it has no effect on HSL execution (other than perhaps being logged or otherwise displayed).

annotate(comment)

where:

  • comment is a comment string.

delay#

Delay HSL execution by the specified number of microseconds.

delay(delay_in_usec)

where:

  • delay_in_usec is the number of microseconds to delay.

writeConstantToMemory#

Write a constant byte value to a memory block.

writeConstantToMemory(constant, memoryBlock, memoryOffset)

where:

  • constant is the byte value to write.

  • memoryBlock is the MemoryBlock object in which to write the constant.

  • memoryOffset is the offset within memoryBlock where the constant will be stored.

If memoryBlock has an associated MemoryLayout, the alternate form may be used:

writeConstantToMemory(constant, memoryBlock.fieldName)

where:

  • memoryBlock.fieldName is the location where the constant will be stored. fieldName must be the name of a 1-byte field in the associated MemoryLayout.

writeTimestampToMemory#

Write an 8-byte timestamp value to a memory block. This value is little endian and represents nanoseconds.

writeTimestampToMemory(memoryBlock, memoryOffset)

where:

  • memoryBlock is the MemoryBlock object in which to write the timestamp.

  • memoryOffset is the offset within memoryBlock where the timestamp will be stored.

If memoryBlock has an associated MemoryLayout, the alternate form may be used:

writeTimestampToMemory(memoryBlock.fieldName)

where:

  • memoryBlock.fieldName is the location where the timestamp will be stored. fieldName must be the name of an 8-byte field in the associated MemoryLayout.