-
-
Notifications
You must be signed in to change notification settings - Fork 600
I2C external device driver integration
Important
Always check the wiring, because you can kill your devices!
On boot, the system will do a full I2C bus scan, and try to find each device it's driver. If a driver is not found, it won't look for it again. The scan is repeated only on main screen and by any app that requests it. If your app requires the periodical scan for new devices you can enable it but disable it in the destructor! These scans will detect new devices and device removals. Devices will be removed when the I2C communication to it's address fails multiple times in a row. If the device is removed, but found again (like plugged in again) the driver will be started again for it. Any app can get a pointer for any driver, and call it's public functions, so it is not forced to just use the update() polling method. But for this, you should write it's own app. The app is preferred to be external app.
The namespace is i2cdev, there is everything you'll need. Currently all drivers are under the firmware/common folder. You can take the i2cdev_bmx280 as an example. It has tons of comments that will help you. Important files:
- i2cdevmanager.hpp - the core of everything. It describes the I2cDev, and the I2CDevManager.
- i2cdevlist.hpp - here you must put your new driver.
- i2cdev_xxxxxx.hpp + cpp - the driver itself.
- Get a good name for your module. From now we will use I2CDEVMDL_EXAMPLEDEV
- Insert a new enum element into the i2cdevlist.hpp at the END of the enum I2C_DEVMDL. Also create define for the dev's I2C address (for all if it has multiple). This should be I2CDEV_EXAMPLEDEV_ADDR_1 , I2CDEV_EXAMPLEDEV_ADDR_2, ...
- Create the new i2cdev_exampledev.hpp and i2cdev_exampledev.cpp files. Use the namespace i2cdev!
- Create the class for the device named I2cDev_ExampleDev, and derive it from I2cDev.
- Override the bool init(uint8_t addr) function. This function must check the address it got if the module uses it. If yes, then try to init the device. Query for any special registers that you can identify the dev, to make sure it is THAT device you are writing the driver for (since different devices share the same address sometimes). If THAT is your device, then set it up and get it ready to go. Also you must return true if the driver is ok. If there is ANY error, you must return false. In this function you MUST set the variable addr to the given address (addr = addr_;). You MUST set the model variable to the new enum you just created. Also you need to set the query_interval value, how often does your device needs to be polled for new data. Don't put here too small value, since it'll slow down the whole system. The value is in seconds. You can use the I2cDev::i2c_read() and i2c_write() functions or one of the helper functions to read / write from the bus. init() must be as fast as possible.
- Override the void update() function. Here you query your device for new data. If you got any value, then you broadcast it system wide. (see next step). update() must be as fast as possible. Try not to delay there. So please don't run calibration code that took 1000 samples and 10 seconds.
- Select the message you want to use. The current system wide messages are in the message.hpp. If you don't find any that fits your need, you can create a new one. (try to avoid that).
- In your update() code just create a new message variable you have selected, take for example the EnvironmentDataMessage msg{temp, hum, pressure}; fill it with your data, and send it to the system with the EventDispatcher::send_message(msg); function.
- Include your hpp file (i2cdev_exampledev.hpp) in the i2cdevmanager.cpp. Then add it to the found() function. There check if the currently found device's address matches any you can handle, and it yes, create an instance of your class (item.dev = std::make_unique<I2cDev_ExampleDev>()) , and try to call init(). If it fails, set the item.dev = nullptr so other drivers can try to work with it.
- Update apps / create apps to handle your data.
- Test, test and test.
- Clean up your code. Remove any unneeded things, use the less needed variable sizes. Try to use the less FW space and RAM. There is not so much ram assigned to this task.
You can use the Debug / ExtSensor app to see what I2C devices are found by the system. You can use the usb_serial_asyncmsg.hpp to send debug messages to USB serial. (before you must send "asyncmsg enable").
I2CDevManager::manual_scan() will start an one time scan for new (or removed) devices. I2CDevManager::set_autoscan_interval() will start a periodic search for new devices. DON'T FORGET TO SET IT TO 0 when you finished or your app is closed! I2CDevManager::get_dev_by_addr(), I2CDevManager::get_dev_by_model() will give you a pointer to the device. Preferred to use the get_dev_by_model(), since with that you'll know what that pointer needs to be casted (it'll return a generic I2cDev, that you derived your driver from). I2CDevManager::get_dev_list_by_model() and I2CDevManager::get_gev_list_by_addr() returns a vector of the models it discovered (that HAS WORKING DRIVER) and all the addresses it sees on the bus (even those without a driver). When the scan detects any change in the device list it'll send a "I2CDevListChangedMessage" system wide message.
Note
The wiki is incomplete. Please add content and collaborate.
Important
- This is a public wiki. Everything is visible to everyone. Don't use it for personal notes.
- Avoid linking to external tutorials/articles; they may become outdated or contain false information.
How to collaborate
How to ask questions correctly
- First steps
- Usage cautions
- Intended use and Legality
- Features
- PortaPack Versions (which one to buy)
- HackRF Versions
- Firmware update procedure
- Description of the hardware
- User interface
- Powering the PortaPack
-
Troubleshooting
- Won't boot
- Config Menu
- Firmware upgrade
- Diagnose firmware update in Windows
- Receive Quality Issues
- No TX/RX
- TX Carrier Only
- H2+ speaker modifications
- Dead Coin Cell Battery
- Factory Defaults
- SD card not recognized by PC with the SD-card over USB selected
- DFU overlay
- Full reset
- SolveBoard
- How to Format SDCard
- Applications
-
Compilation of the firmware
- Compile on WSL with ninja
- How to compile on Windows faster with WSL 2
- Using Docker and Kitematic
- Docker command-line reference
- Using Buddyworks and other CI platforms
- Notes for Buddy.Works (and other CI platforms)
- Using ARM on Debian host
- All in one script for ARM on Debian host
- Compile on Arch based distro (exclude Asahi)
- Dev build versions
- Notes About ccache
- Create a custom map
- Code formatting
- PR process
- Description of the Structure
- Software Dev Guides
- Tools
- Research
- UI Screenshots
- Maintaining
- Creating a prod/stable release (Maintainers only)
- Maintaining rules
- Development States Notes