rust-embedded / wg

Coordination repository of the embedded devices Working Group
1.9k stars 99 forks source link

The weekly driver initiative #39

Closed japaric closed 4 years ago

japaric commented 6 years ago

There's now a HAL published on crates.io: embedded-hal (Introduction blog post). :tada:

To put it to test and to expand the crates.io ecosystem I'm starting the weekly driver initiative.

The goal is to release a new no_std, generic, embedded-hal based driver crate every one or two weeks. Driver crate here means a library crate that lets you interface an external component like a digital sensor or a wireless transceiver. A driver release consists of (a) publishing a library crate on crates.io (*) and (b) presenting your driver to the community via any means: a blog post, a tweet, a reddit post, a u.r-l.o https://users.rust-lang.org post, etc.

(*) Make sure you tag your crate with the embedded-hal-driver keyword!

If you'd like to participate leave a comment here stating the driver you'll be working on. If you can post a link to the repo where the (WIP) driver code is or will be, even better! If you don't have a personal blog to present your driver to the community you can do a guest post on my blog.

For a list of released and WIP drivers check the awesome-embedded-rust list. If you'd like your crate to be added to that list simply send a PR to that repo!

TODO (potentially):

These are components that @japaric has at hand:

jamesmunns commented 6 years ago

I will be working on an embedded-hal driver for the Decawave DW1000 module (which should also support the DWM1000 and DWM1001 modules), which is an 802.15.4 compatible UWB (3.5-6.5GHz) SPI based radio chip.

Right now the (verrrrry little) code lives here: https://github.com/jamesmunns/raumfahrer/tree/master/src/dw1000 (living next to the application code), but once it is a bit further along, I will break it out and put it up on crates.io.

It is a very complex module, so the development will be ongoing, but I hope to have support for at least basic ranging use cases in the near future (hopefully weeks).

odlg commented 6 years ago

I am working on a RFM95W/RFM96W lora driver, which are actually based on SX1276/SX1278 modules. So far the driver is going to be without interrupt handling, but that might be added later.

nordmoen commented 6 years ago

I'm implementing drivers for HC-SR04 and VL6180. The HC-SR04 driver will initially be married to the f3 crate because there are no general timers to estimate length of time. Once I have tested a bit with the f3 I want to try and generalize the needed timers and have them included in embedded-hal.

MrBuddyCasino commented 6 years ago

Wanted to make a driver to improve my Rust skills, but it seems there is only an SPI implementation. Any idea when I2C module will be available?

therealprof commented 6 years ago

@MrBuddyCasino I2C traits do exist and some HALs also have I2C support. Anything specific you think is missing?

MrBuddyCasino commented 6 years ago

No, I just saw an SPI module but no I2C module. Got a link as starting point?

therealprof commented 6 years ago

@MrBuddyCasino See the top comment in this thread?

The embedded-hal trait is here: https://github.com/japaric/embedded-hal/blob/master/src/blocking/i2c.rs

Support is available at least for some stm32 MCU and e.g. for the nrf51. Which ones are you trying to use?

MrBuddyCasino commented 6 years ago

Totally missed that, thx. I was referring to https://docs.rs/embedded-hal/0.1.2/embedded_hal/#modules which is what confused me.

I've got some blue pill boards, I'll just try and see.

MrBuddyCasino commented 6 years ago

So I'm trying my hands on the MCP9808 temperature sensor. The I2C sorcery required to read a value is this:

i2c_start();                         // send START command
i2c_write (AddressByte & 0xFE);     //WRITE Command 
i2c_write(0x05);                    // Write TA Register Address
i2c_start();                        //Repeat START
i2c_write(AddressByte | 0x01);      // READ Command 

//also, make sure bit 0 is Set ‘1’
UpperByte = i2c_read(ACK);          // READ 8 bits 
//and Send ACK bit
LowerByte = i2c_read(NAK);          // READ 8 bits 
//and Send NAK bit
i2c_stop();                         // send STOP command

The Rust I2C trait only lets me do Readand Write operations, with automatic start and stop commands. But it looks like I need to have control over start and stop commands in order to implement the required protocol. Anyone got an idea? Is there a better place to discuss these issues than this issue?

MrBuddyCasino commented 6 years ago

The Python I2C module supports start/stop parameters, maybe the Rust HAL could be extended? This is how they do it:

        self.buf[0] = 0x05
        with self.i2c_device as i2c:
            i2c.write(self.buf, end=1, stop=False)
            i2c.readinto(self.buf, start=1)

Source: https://github.com/adafruit/Adafruit_CircuitPython_MCP9808/blob/master/adafruit_mcp9808.py

kunerd commented 6 years ago

@MrBuddyCasino: It seems, that the read/write functions from the embedded-hal traits accept u8 Slices, so you should be able to send and receive more then one byte without sending stop commands. Anyhow, a better place to discuss this would be users.rust or the #rust-embedded channel, I think.

MrBuddyCasino commented 6 years ago

I'm not an I2C expert, but start/stop conditions are transitions of SDA while SCL is high, while during regular data transmissions, SDA is only allowed to change while SCL is low and remains stable when SCL is high. So I suspect that won't work.

Trying my luck in #rust-embedded, thanks!

burrbull commented 6 years ago

@MrBuddyCasino I think you need something like this.

let mut buff: [u8; 2] = unsafe { mem::uninitialized() };
self.i2c.write_read(AddressByte >> 1, &[0x05], &mut buff)?;
let (UpperByte, LowerByte) = (buff[0], buff[1]);
MrBuddyCasino commented 6 years ago

Thats exactly the code I came up with :)

dbrgn commented 6 years ago

I started writing a driver for the SHT{21,22,25} temperature/humidity sensors: https://github.com/dbrgn/sht2x-rs

The code is very much inspired by @wose (nice and clean code for the SI7021!). It seems that the SI7021 made their sensor compatible to the SHT2x, correct? I'd suspect that it still makes sense to create a separate driver though (there might be some details that differ?), unless @wose can convince me of the opposite.

(Edit: For example, it seems that the SI7021 has separate I2C commands to control the heating element, while the SHT2x uses the user register for that, correct?)

wose commented 6 years ago

@dbrgn I think the SHT2x (and HTUxx) can and should be supported by the si7021 driver crate. Actually, measurements should already work if you're using this. The SHT and HTU sensors support a subset of the SI7021 features. The heater control (on/off) is controlled by the same bit (bit 2 of the UserReg) for SI, SHT and HTU, but the SI7021 has an additional register to configure the heater. There are some other differences, but they could all be fleshed out as separate traits and implemented for those sensors who support the feature. At least that's what I had planned to do... soon-ish.


I'm still unsure about how we should name sensor crates which support many sensors from different vendors:

I tend to keep the name as si7021 is the sensor of this family with the most features (AFAIK) and add all other supported sensors to the documentation and as keywords so they are discoverable.

hannobraun commented 6 years ago

@wose

I'm still unsure about how we should name sensor crates which support many sensors from different vendors

Idea: Create one crate per supported sensor, make their names extremely specific. Have all those crates consist of a single statement that re-exports everything from a weirdly named master crate.

(Not sure myself how serious I am with this suggestion. Seems a bit spammy, but definitely helps with discoverability.)

lnicola commented 6 years ago

Wouldn't crates.io/Cargo.toml keywords work for this?

hannobraun commented 6 years ago

@lnicola To a degree, yes. But if the crate name is either too general, or specific to the wrong sensor, then a potential user might be put off at first sight, simply because they don't understand that this is the crate they need.

lnicola commented 6 years ago

@hannobraun The description field (and a README) can probably clear things up, as the first is shown in the crates.io search results, and the latter is visible on the crate page and most likely in the source repository.

I feel that making a generic crate, then one per sensor would create more confusion.

Anyway, this seems a bit off-topic, maybe we could create another issue for defining some guidelines about discoverability and handling similar devices?

hannobraun commented 6 years ago

@lnicola

Anyway, this seems a bit off-topic, maybe we could create another issue for defining some guidelines about discoverability and handling similar devices?

Good idea! Could you open an issue an tag me there? I would do it myself, but I'm on my way to bed right now (and would already be there, if I hadn't left my email client open :-) ).

davidtibbetts commented 6 years ago

Great to hear about what everyone is working on! I hope everyone is as excited as I am. I've pushed my first PR on the stm32f103xx-hal repo (#56) to support the different flash/ram densities on that chip. It works, but can be better. This is also a prelude to my plan to tackle stm32f103xx-hal Issue #37 to specify pin configurations.

kunerd commented 6 years ago

I have finally started to re-factor my HD44780 driver clerk to use the traits from embedded-hal. The good news, it was really easy to get it working on STM32 (arm-cortex), without the embedded-hal traits at first. After that I was able to replace my custom Delay trait with the one from embedded-hal. If anyone is interested, there is an issue for discussion and tracking the current state of this re-factoring.

therealprof commented 6 years ago

Just posted a new driver for the I2C based TI INA260 power monitor. It's available here: https://crates.io/crates/ina260

getreu commented 6 years ago

Drivers should be published under the same license as embedded-hal and cortex-m-rtfm which is:

Licensed under either of

It is important that the ecosystem grows under the same license! If you agree with me, the question arises if and how we could enforce this?

One way to go: We set up an "official repository" to create an incitement for developers to become part of it. License compliance would be the first condition to get a driver accepted. In case we later add quality criteria as acceptance condition, this "official repository" should be managed in a democratic way.

@therealprof Could you consider adapting your license to Apache/MIT?

thejpster commented 6 years ago

Actually I disagree. The Author of a work must always be free to license that work in any way they see fit. We can certainly suggest MIT/Apache 2, for good reasons, but if someone wants to use PD, or BSD, or GPL3, then that's their choice.

therealprof commented 6 years ago

@getreu I really don't care too much about licensing. I picked 0BSD at some point because it seems to be one of the most liberal licenses out there and explicitly excludes liability which is really the only thing I actually do care about. I absolutely don't want to waste my time with licensing crap and games, so love it or leave it; or if you really care: take the source and re-release it under a different license -- 0BSD allows you to do that.

getreu commented 6 years ago

In a professional environment the license is of utmost importance. When you start a project and choose an ecosystem for embedded development you need to make sure that all code and drivers are released under a compatible license.

A common license policy is not only supporting our vision (To improve the productivity of embedded software development teams) but also constitutes the condition sine qua non for professional suitability. Linux wouldn't have been successful in a professional environment without a common license policy.

dbrgn commented 6 years ago

@getreu yes, the use of permissive licenses (which are generally compatible among each other) is important if you want your code to be used by companies. however, whether the library authors use MIT, or BSD, or Apache 2, or a combination of them or something else, should be up to them.

therealprof commented 6 years ago

@getreu Compatible: yes, identical: no. And I absolutely don't get your "Linux" point, are you talking about the kernel or the ecosystem?

MrBuddyCasino commented 6 years ago

Embedded work is often Big Company work, and I've learned they hate one thing: the GPL (even LGPL). Never had issues with the permissive ones, be it MIT / BSD / Apache / Mozilla or whatever, so I don't see the value of enforcing a standard.

So maybe no GPL and a suggested but not required permissive standard license?

getreu commented 6 years ago

@therealprof

Compatible: yes, identical: no.

@MrBuddyCasino

Never had issues with the permissive ones, be it MIT / BSD / Apache / Mozilla or whatever

A license is a legal agreement. Unfortunately "permissive" and "compatible" are no legal concepts. In general when someone assembles code with different licences, he needs to make sure that his usage does not violate any of the licences. In other words, you have to comply with all of them. This needs to checked against the business model that is subject to change. Without a layer next to you, many different licenses becomes a risky enterprise because your attack surface gets bigger with every licence you add to your code base. In doubt professionals will not opt for an ecosystem where the legal side is risky or somehow unclear.

@therealprof

And I absolutely don't get your "Linux" point, are you talking about the kernel or the ecosystem?

Kernel.

MrBuddyCasino commented 6 years ago

In doubt professionals will not opt for an ecosystem where the legal side is risky or somehow unclear.

Is this something you have experienced or something that you think might be an issue?

getreu commented 6 years ago

If we all agree with: @dbrgn

yes, the use of permissive licenses

... it should not hurt anybody to chose the same than the Rust language and RTFM. A professional user will always prefer a code base with a coherent, simple and clear license policy.

therealprof commented 6 years ago

@getreu As an OSS developer and "professional" user for well over 20 years now I find your authoritative stance rather disconcerting. I deserve the right to publish my code under which ever license I please, especially when it's even clearer, simpler and more permissive than the ones suggested here.

jamesmunns commented 6 years ago

@getreu @therealprof @dbrgn @MrBuddyCasino

Would you mind opening up a separate issue to discuss this? It seems that there are a couple different views here, and it might make sense to discuss that in a single place, rather than on this issue.

thejpster commented 6 years ago

it should not hurt anybody to chose the same than the Rust language and RTFM. A professional user will always prefer a code base with a common simple and clear license policy.

Open source is about freedom. We should make a recommendation but accept that it is up to the author to choose who to grant access to their work - work which we are extremely grateful to them for performing and sharing with the world.

Yes collecting open source licences is a pain, but having all components under the same licence doesn't help that much as they all have unique copyright strings that be to be included with any documentation supplied with the product. At that point I really couldn't care less whether a component was Apache 2, MIT or BSD - my workload is the same. GPL is obviously typically a barrier to commercial user in an embedded single-image product which also includes proprietary code, but frankly if it's a choice between a GPL, say, humidity sensor driver, or no driver, as a community we should take the GPL one and say thank you! If that's ever a problem for anyone in the future they are very welcome to write their own or buy a commercial licence; if they wish to sell a commercial wall mounted humidity sensors, then they probably have the resources to do just that.

I almost never come across components that do not have a common, simple or clear license policy. The only cases I do, it's when no licence has been specified. We should obviously discourage that.

Be conservative in what you do, be liberal in what you accept from others.

  • Postel's Law
getreu commented 6 years ago

@therealprof Yes, you deserve it!

My claim is that a coherent, simple and permissive license policy helps to introduce this project in the professional space.

thejpster commented 6 years ago

Would you mind opening up a separate issue to discuss this?

Agreed.

getreu commented 6 years ago

Would you mind opening up a separate issue to discuss this?

Agreed. I opened #57 and copied my comments there. @thejpster , @dbrgn , @jamesmunns , @MrBuddyCasino , @therealprof : if you could do the same then your arguments will not get lost.

rahul-thakoor commented 6 years ago

I am planning on doing an I2C driver for JHD1313M1 Controller for HD44780-based Displays and an I2C driver for MMA7660FC based 3-Axis Digital Accelerometer(±1.5g)? Is anyone already working on this?

kunerd commented 6 years ago

@rahul-thakoor I don't know how the JHD1313M1 controller works, but if it only uses a non-parallel interface and the same control codes as specified in HD44780 spec, then you could use my driver clerk and you only would have to implement a couple of traits (currently three I think).

rahul-thakoor commented 6 years ago

@kunerd Hey thx! I believe you are refactoring the driver to be embedded-halcompatible. I will try the implementation for JHD1313M1 controller later on

scowcron commented 6 years ago

I'm working on an ssd1306 driver here

therealprof commented 6 years ago

@scowcron Great stuff. I guess you beat me to it and it's much cleaner than my version. Have to check whether I can use my character display on top of it.

scowcron commented 6 years ago

@therealprof thanks, still WIP but it's getting close to 0.1

dbrgn commented 6 years ago

Here's my MCP3425 driver. It's a low-current 16-bit I²C ADC with an internal voltage reference.

The driver is not yet fully done, so far only one-shot measurements work. I'll have to look into continuous mode, but I'm not actually sure how nicely that's implementable with a blocking API.

By the way, is there a nice way to mock the embedded-hal APIs? I'd like to unit test my library with different I²C return values to make sure that the detection of positive/negative saturation works properly...

dbrgn commented 6 years ago

Ok, I finished the implementation of the MCP3425 driver. Feedback is welcome. Now I have a few comments and questions about the implementation (exploring the design space). It's probably a bit long, but might be interesting for other driver implementations.

Any feedback is very welcome, since I'm using this driver as a playground to learn to write a device driver in Rust that's as close to perfect as possible :slightly_smiling_face:

(Edit: Moved text to separate issues at https://github.com/dbrgn/mcp3425-rs/issues)

japaric commented 6 years ago

@therealprof (ina260, mag3110) @yuri91 (ili9341) @dbrgn (mcp3425)

Y'all have release a driver crate on crates.io tagged with the embedded-hal-driver keyword. If any of you doesn't plan to do a blog post or any other kind of announcement about your driver crate let me know so that I can move your crate to the "Released" list! (see issue description).

@dbrgn I would suggest moving your comment to the issue tracker of your driver crate and continuing the discussion there; otherwise this thread will to go off topic.

Low level I²C access

That sounds like something that japaric/embedded-hal#50 might be able to handle.

therealprof commented 6 years ago

@japaric No plans to do a blog article on the INA260 alone. I wanted to create an application using the INA260 and the SSD1306 and write a blog article about writing real world applications but this is blocked on a decent solution for japaric/embedded-hal#35.