mrt-device
The mrt-device tool allows user to create driver code from device description files. This provides very consistent drivers and also creates an easily parseable device file as a byproduct. This can be used for better documentation as well as a basis for automated testing of hardware.
Note
The code generated from this tool requires the Mrt RegDev module
Step 1: Define device:
Devices are defined with a YAML file.
To generate a blank template to start from:
mrt-device -t /path/to/file.yml
example from hts221 driver
---
name: HTS221
description: Humidity and Temperature Sensor
category: Device
requires: [RegDevice,Platform]
datasheet: https://www.st.com/content/ccc/resource/technical/document/datasheet/4d/9a/9c/ad/25/07/42/34/DM00116291.pdf/files/DM00116291.pdf/jcr:content/translations/en.DM00116291.pdf
mfr: STMicroelectronics
mfr_pn: HTS221TR
digikey_pn: 497-15382-1-ND
prefix: HTS
bus: I2C
i2c_addr: 0xBE
###########################################################################################################
# Registers #
###########################################################################################################
registers:
- WHO_AM_I: { addr: 0x0F , type: uint8_t, perm: R, desc: Id Register, default: 0xBC}
- AV_CONF: { addr: 0x10 , type: uint8_t, perm: RW, desc: Humidity and temperature resolution mode}
- CTRL1: { addr: 0x20 , type: uint8_t, perm: RW, desc: Control register 1}
- CTRL2: { addr: 0x21 , type: uint8_t, perm: RW, desc: Control register 2}
- CTRL3: { addr: 0x22 , type: uint8_t, perm: RW, desc: Control register 3}
- STATUS: { addr: 0x27 , type: uint8_t, perm: R, desc: Status register}
- HUMIDITY_OUT: { addr: 0x28 , type: int16_t, perm: R, desc: Relative humidity data }
- TEMP_OUT: { addr: 0x2A , type: int16_t, perm: R, desc: Temperature data}
- H0_rH_x2: { addr: 0x30 , type: uint8_t, perm: R, desc: Calibration data}
- H1_rH_x2: { addr: 0x31 , type: uint8_t, perm: R, desc: Calibration data}
- T0_DEGC_x8: { addr: 0x32 , type: uint8_t, perm: R, desc: Calibration data}
- T1_DEGC_x8: { addr: 0x33 , type: uint8_t, perm: R, desc: Calibration data}
- T1T0_MSB: { addr: 0x35 , type: uint8_t, perm: R, desc: Calibration data}
- H0_T0_OUT: { addr: 0x36 , type: int16_t, perm: R, desc: Calibration data}
- H1_T0_OUT: { addr: 0x3A , type: int16_t, perm: R, desc: Calibration data}
- T0_OUT: { addr: 0x3C , type: int16_t, perm: R, desc: Calibration data}
- T1_OUT: { addr: 0x3E , type: int16_t, perm: R, desc: Calibration data}
###########################################################################################################
# FIELDS #
###########################################################################################################
fields:
- STATUS:
- TEMP_READY: { mask: 0x01, desc: indicates that a temperature reading is ready }
- HUM_READY: { mask: 0x02, desc: indicates that a humidity reading is ready }
- CTRL1:
- PD: {mask: 0x80, desc: power down mode}
- BDU: {mask: 0x04, desc: Block Data update. Prevents update until LSB of data is read}
- ODR:
mask: 0x03
desc: Selects the Output rate for the sensor data
vals:
- ONESHOT: { val: 0, desc: readings must be requested}
- 1HZ: { val: 1, desc: 1 hz sampling}
- 7HZ: { val: 2, desc: 7 hz sampling}
- 12_5HZ: { val: 3, desc: 12.5 hz sampling}
- CTRL2:
- BOOT: {mask: 0x80, desc: Reboot memory content}
- HEATER: {mask: 0x02, desc: Enable intenal heating element}
- ONESHOT: {mask: 0x01, desc: Start conversion for new data}
- TEMP_OUT:
- TEMP_OUT: {mask: 0xFFFF, desc: Current ADC reading for temperature sensor}
- HUMIDITY_OUT:
- HUM_OUT: {mask: 0xFFFF, desc: Current ADC reading for humidity sensor}
###########################################################################################################
# Preset Configs #
###########################################################################################################
configs:
- auto_1hz:
desc: Sets device to update every second
registers:
- CTRL2: {BOOT: 1, delay: 20} #20 ms delay after register write
- CTRL1: { ODR: 1HZ, BDU: 1}
The descriptor file contains device information such as part numbers, links to datashees, and other relevant information. It also contains definitions of registers and data structures on the device. The main sections are Header Properties , Registers , and Fields
Header Properties
The header of the descriptor file contains several Properties. name
and description
are required, but others should also be included if they apply
- name:
Name of device
- description:
Description of device
- datasheet:
url to public datasheet
- mfr:
Name of manufacturer
- mfr_pn:
Manufacturer part number
- digikey_pn:
Digikey part number
- prefix:
prefix to append to struct and function names to prevent conflicts in projects
- bus:
bus type for driver, can be
I2C
,SPI
,UART
, or any combination of those (comma separated)- i2c_addr:
I2C address for device. For devices with configurable address, set this to the base address. It can be changed in the driver
Registers
registers
are individualy addressable memory registers on the device. each register can have the folowing attributes:
addr: register address on device
type: register type, (default is uin8_t)
perm: premissions on register R for read, W for write
desc: description of register. used for code documentation
default: default value of the register
Fields
fields
are data fields contained in registers. They are grouped by register and they contain the following attributes:
mask : this specifies the mask for the field. This is used to mask and shift data to match the field.
vals : this is a list of possible values and their descriptions for the field.
Note
If a field is defined with a single bit mask, and no values, it is interpretted as a ‘flag’. Flag fields have macros generated for setting, clearing, and checking them.
Configs
Configs
allow the user to define preset configs for common use cases. This will create a macro for setting up the registers
/**
* @brief Sets device to update every second
* @param dev ptr to HTS221 device
*/
#define HTS_LOAD_CONFIG_AUTO_1HZ(dev) \
hts_write_reg( (dev), &(dev)->mCtrl2, 0x80); /* BOOT: 1 */ \
MRT_DELAY_MS(20); /* Delay for CTRL2 */ \
hts_write_reg( (dev), &(dev)->mCtrl1, 0x05); /* ODR: 1HZ , BDU: 1 */ \
Step 2: generate the code
To generate the code, use mrt-device and specify an input and an output path:
mrt-device -i device.yaml -o .
The tool will generate 3 files (using hts221 as an example):
hts221.h : header file for driver
hts221.c : Source file for driver
hts221_dev.h : Macros generated from device file. this contains macros for addresses, values, masks, and functions for accessing fields/flags in registers.
Step 3: customize
This will provide a good base with access to all of the register. To add more functionality you can add to the code. If you want to ability to modify the device file further, keep your code inside of the ‘user code’ blocks provided:
/*user-block-init-start*/
/*user-block-init-end*/
If the device does not follow the normal register access schemes, you can specify your own, and redirect the mrt_regdev_t fRead and fWrite function pointers to them.
/**
*@brief writes buffer to address of device
*@param dev ptr to generic register device
*@param addr address in memory to write
*@param data ptr to data to be written
*param len length of data to write
*@return status (type defined by platform)
*/
mrt_status_t my_write_function(mrt_regdev_t* dev, uint32_t addr, uint8_t* data,int len )
{
//Do Something
}
static mrt_status_t hts_init(hts221_t* dev)
{
/*user-block-init-start*/
dev->mRegDev.fWrite = my_write_function;
/*user-block-init-end*/
return MRT_STATUS_OK;
}