Skip to content
Brainless-SoftwarePublic

About

Python classes for accessing registers on embedded devices

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

RGSCore

License - MIT PyPI Latest Release pytest Documentation

Python library that provides classes for representing, defining and accessing registers in the embedded devices.

To add this library to your project do

uv add rgscore

Library purpose

  1. To provide python API to define registers and serialize it into persistent json store/file.
  2. To provide access from Python to serialized form of register definitions (aka. addrMap json).
  3. Together with other libraries, such as i2c-api and i2c-drivers, to provide read and write access from Python to registers in live devices.

Overall structure

To fulfill above goals this library defines following classes

  • Register - defines/holds name, address, description, in-memory bitarray storage, reset value and a model of fields (list of FieldDef objects).
  • FieldDef - holds register field definition which includes field name, bit-range in the larger register bitarray, numeric type, r/w flag, description and optional enum values that maps numeric value held in a register field to symbolic names.
  • EnumValue - symbolic name corresponding to a numeric value in the field. Also includes description.
  • RLink - abstract class that connects registers to physical hardware. Requires implementation that drives low level communication to live device.
  • RLinkI2C - implementation of RLink suitable for linking classes in this library to physical devices over I2C bus.
  • AddrMap - grouping of registers ensuring their uniqueness within addrMap. Primary class for (de)serialization to/from json file.

Defining registers programmatically

Registers are grouped into ordered collections known as addrMap's, represented by AddrMap class. When registers are added to the addrMap this ensures that they are unique (both, with regard to register names and addresses) within a given addrMap. Registers can be added to the addrMap at the time of construction or later by calling AddrMap::add(...) method.

from rgscore import Register, AddrMap, FieldDef, EnumValue

addrMap = AddrMap(registers=[
    Register(
        bit_len=8,
        name="Foo",
        address=0x01,
        desc="Register Foo",
        model=[FieldDef.value_of("a@[3:0]U4.1#ro")]
    )
])

addrMap.add(Register(
    bit_len=8,
    name="Bar",
    address=0x02,
    model=[
        FieldDef.value_of("b@[3:0]U4.0#ro").with_description("field b").with_enum(
            [EnumValue("START", 1, "Starting..."), EnumValue("STOP", 0, "Stoping...")]
        )
    ],
))

AddrMap ensures that registers do not have overlapping names or addresses.

Class Register holds

  • name - optional human-readable name.
  • address - optional integer address within larger address space.
  • desc - optional description.
  • reset - reset value (default is 0x0)
  • bit_len - bit width.
  • address_bus_width_bytes - width of the address bus (default is 1).
  • model - optional model of register fields, i.e. an array of FieldDef instances.
  • link_provider - optional prover of RLink, object that links this register to the physical hardware.

If model is None, then model with just one field spanning the whole of the register width is autogenerated with numerical type of unsigned int.

When adding it to the AddrMap it must have an address. If name is not present, then adding it to the AddrMap will autogenerate name in the format R${hex_address}.

Class FieldDef can be created using string description by calling FieldDef.value_of(...). Where description is

<field_name>@<bit_range><num_type>

or

<field_name>@<bit_range><num_type>#<rw_flag>

where <bit_range> is [<end_offset>,<start_offset>]

<num_type> is fixed point number definition in simplified Q_(number_format), i.e. U or S (for unsigned or signed) followed by bit-width, then dot, and then fraction.

Flag <rw_flag> is optional and can be "rw" (default) or "ro".

Description can be added by calling with_description(...) and enum values with_enum(...)

Loading addrMap from json file

Instance of AddrMap can writen down into json file and read back like so

from pathlib import Path
from rgscore import AddrMap

addrMap = AddrMap(...)

# write into a file
addrMapFilePath = Path.home() / "addrMap.json"
addrMap.save_to_json_file(addrMapFilePath)

# load from a file
addrMap = AddrMap.new_instance_from_file(addrMapFilePath.read_text())

Loading addrMap from URL

AddrMap class can be instantiated with the URL that points to addrMap json file.

from rgscore import AddrMap

addrMap = AddrMap.new_instance_from_url("https://.../addrMap.json")

By default, this will cache downloaded json file at $HOME/.rgscore/cache/ directory, so that subsequent calls to this function will load addrMap from cache. Cache can be refreshed if force_reload=True argument is set.

To change cache location you can set RGSCORE_CACHE_DIR environment variable to another folder.

Accessing registers on physical devices

To access physical hardware you need to create instance of RLink that links AddrMap (and therefore registers) to live chip over some physical bus. Below is an example of doing that over I2C bus. This requires you to bring in two more libraries, i2c-api and i2c-drivers.

from i2c_drivers import I2CMasterI2CDriver

from rgscore import AddrMap, RLinkI2C

regList = AddrMap.new_instance_from_file("regList-BMP581.json", link=RLinkI2C(I2CMasterI2CDriver(), 0x47))

odr_config = regList.get_register_by_name("ODR_CONFIG")
odr_config.read()  # read from the chip at I2C address 0x47
print("pwr_mode", odr_config.get_field_value("pwr_mode"))

# set new pwr_mode and write this register to the chip
odr_config.set_field_value("pwr_mode", 1)
odr_config.write()

About

Python classes for accessing registers on embedded devices

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages