<slabity[m]>
Cool, so I have been able to get a handful of the `embassy_rp` examples running. Everything is good so far 👍️
<slabity[m]>
However, I'm looking to try and get an i2c device working (an ADS1115 board) and I am wondering, is it possible to use the `ads1x1x` crate in embassy? It looks like it's based on the `embedded-hal` traits so I am not sure how well that integrates into the `embassy` ecosystem.
<dirbaio[m]>
<slabity[m]> "Cool, so I have been able to get..." <- > <@slabity:matrix.org> Cool, so I have been able to get a handful of the `embassy_rp` examples running. Everything is good so far 👍️
<dirbaio[m]>
> However, I'm looking to try and get an i2c device working (an ADS1115 board) and I am wondering, is it possible to use the `ads1x1x` crate in embassy? It looks like it's based on the `embedded-hal` traits so I am not sure how well that integrates into the `embassy` ecosystem.
<dirbaio[m]>
The embassy hals implement the embedded-hal traits, just like any other hal. So it should work out of the box
<cr1901>
Answer... I needed to compile the hal with unproven
<cr1901>
feature*, not _just_ the embedded-hal traits
crabbedhaloablut has quit [Quit: No Ping reply in 180 seconds.]
crabbedhaloablut has joined #rust-embedded
exark has quit [Quit: quit]
exark has joined #rust-embedded
<slabity[m]>
<dirbaio[m]> "> <@slabity:matrix.org> Cool, so..." <- Yea, the problem is I don't really see any examples of embassy programs using these sort of drivers so I am not sure if I'm doing this right
<slabity[m]>
Tried doing it blocking as well (instead of I2c::new_async) to see if that might be the issue, but same result
<slabity[m]>
I'll try asking in the rp-rs channel as well. Might be more relevant there.
M762spr[m] has joined #rust-embedded
<M762spr[m]>
can someone point me to a good reference on embedded error handling? I'm trying to convert Output and SPI errors to an error enum in my driver and not having any luck 🫠
sneakernet[m] has quit [Quit: Idle timeout reached: 172800s]
<M762spr[m]>
thank you that looks like exactly what I was looking for. I'll give it a try!
<slabity[m]>
<slabity[m]> "I have a program that compiles..." <- Nvm, I didn't realize the RP2040 and RP Pico pinouts were different
<slabity[m]>
Switching to PIN_14 and PIN_15 seems to work
<M762spr[m]>
<GrantM11235[m]> "Use `map_err` like this https..." <- Worked great! Thank you so much! I was getting hung up on the generics for my enum. Makes perfect sense now that I see it to pass them from the function.
pflanze has quit [Read error: Connection reset by peer]
pflanze has joined #rust-embedded
AlexChen[m] has quit [Quit: Idle timeout reached: 172800s]
bomb has joined #rust-embedded
badyjoke[m] has joined #rust-embedded
<badyjoke[m]>
Hello, I want to try to write a driver over SPI for a 6-axis accelerometer, is there any good advice/best practice or example I can look at ?
<JamesMunns[m]>
might be worth looking for ones that were updated recently for `embedded-hal` v1.0
AtleoS has quit [Ping timeout: 255 seconds]
AtleoS has joined #rust-embedded
chrysn[m] has quit [Quit: Idle timeout reached: 172800s]
sarath08071994[m has quit [Quit: Idle timeout reached: 172800s]
<JamesMunns[m]>
Looks like Google and some others are working on a Root of Trust called "Caliptra", and gee that's a lot of Rust in the firmware project: https://github.com/chipsalliance/caliptra-sw
bomb_ has quit [Remote host closed the connection]
bomb_ has joined #rust-embedded
bomb_ is now known as bomb
<dav1d>
With embassy-sync is there a way to return a value when sending an event to a task?
<dirbaio[m]>
"return" from the destination task to the task that sent the event?
<dirbaio[m]>
no
<dirbaio[m]>
you have to use a 2nd channel in the opposite direction for that
<dav1d>
dirbaio[m], thanks - I'd like my http server to ask a task for some values, any idea how I can accomplish that?
<dirbaio[m]>
easiest is to make that task put the values in a global mutex whenever they change
<dirbaio[m]>
so any other task can just grab them from there at any time
<dav1d>
aight, thanks
<dirbaio[m]>
in general it's best to avoid "request-response RPC between tasks" because it causes complexity to explode quite quickly
<dirbaio[m]>
it's easier to share the data, than sending a "request" for it
<dirbaio[m]>
and
<dav1d>
Maybe I should just kill the task and just have everything shared in a global mutex
<dirbaio[m]>
if the data requires "work" to produce that you want to do on-demand (for example you want to read some value from an i2c sensor on-demand when the http request arrives), then put the sensor itself on a mitex
<dirbaio[m]>
s/mitex/mutex/
sourcebox[m] has quit [Quit: Idle timeout reached: 172800s]
<dav1d>
Thanks! Really helpful. I came up with this (https://p.dav1d.de/Hah.rs) to have valves opened/closed for a certain amount of time, the http server would just send Open/Close but now I kind of need a status as well which breaks the pattern
<slabity[m]>
The idea is that the ADC will pulse the ALERT/RDY pin when a reading is available to trigger an interrupt. I haven't set up the interrupt in Rust yet, but for some reason I can't detect the falling edge on the GPIO pin that I plan to use. My Rust program stops at line 63, which means the pin never goes low.
<slabity[m]>
If I manually disconnect/reconnect the pin it will proceed and read the ADC properly. I do not need to do this for the Arduino program
<dirbaio[m]>
try wait_for_low(). wait_for_falling_edge won't detect the edge if it happened before you started waiting
<slabity[m]>
It should be pulsing it at regular intervals, approximately 8 times per second (I set the conversion rate to 8SPS)
<slabity[m]>
And I've tried that unfortunately
<slabity[m]>
I've even tried just reading the pin outright and it never goes low
<dirbaio[m]>
(btw, wait_for_low, wait_for_falling_edge use interrupts internally, you don't have to set up interrupts manually)
<dirbaio[m]>
hmmm
<dirbaio[m]>
so if you do .is_high() you get true always?
<slabity[m]>
Yes
<slabity[m]>
So the pulsing isn't happening. I am feeling like it's a bug in the use_alert_rdy_pin_as_ready function in the ads1x1x crate but I can't figure it out
<slabity[m]>
I am not sure if there's an order of operations that I need to modify the Ads1x1x struct or if I'm not actually applying it or something
<dirbaio[m]>
looks like ads1x1x-specific issue yeah...
<slabity[m]>
I've tried reordering it in a dozen different ways but it just doesn't seem to work no matter how I try.
<slabity[m]>
I can't seem to print out the config either, since embassy_rp::i2c::Blocking doesn't implement Debug for some reason
<dirbaio[m]>
hmm how're you printing it? seems odd that it'd try to print the i2c bus itself
<slabity[m]>
`Ads1x1x` is defined as `pub struct Ads1x1x<DI, IC, CONV, MODE>` and implements `Debug` only if the underlying interface (`DI`, which is that I2c struct) implements it
<slabity[m]>
And the config is defined as pub(crate) config: Config so I can't access the field directly either.
<dirbaio[m]>
ugh that seems some oversight
<dirbaio[m]>
maybe you could change it to a manual impl that doesn't require Debug on the bus, isntead of derive(Debug)
<dirbaio[m]>
or add a dummy Debug impl to embassy-rp
<slabity[m]>
I feel like I've been running into a lot of oversights lately
<dirbaio[m]>
(what's the best practice on this? should HALs impl dummy Debugs on drivers?)
<JamesMunns[m]>
dirbaio[m]: probably, I've stumbled over this before because of derive impls
<slabity[m]>
Yea, I guess I can run a locally modified crate
<slabity[m]>
Maybe just expose that one field as pub
<dirbaio[m]>
that'd work too :D
<dirbaio[m]>
unfortunately I don't have personal experience with the Ads1x1x so I can't help much
<dirbaio[m]>
but if I had to debug this
<dirbaio[m]>
i'd try reading the datasheet, to learn what exact register writes you have to do over i2c to enable use the RDY pin
<dirbaio[m]>
then read the Ads1x1x crate source to verify it matches
<JamesMunns[m]>
yeah, I wrote code for a similar part (ads1110), and the i2c regs for both chips are silly simple
<JamesMunns[m]>
it's like 3x 16 bit registers you can read or write in one stretch
<dirbaio[m]>
perhaps make it print all i2c transfers so you can see them and verify it's actually
<dirbaio[m]>
* it's actually doing the thing it should
<JamesMunns[m]>
(I made another crate because ads1110 is COMPLETELY different from the other chips that are supported by ads1x1x)
<dirbaio[m]>
check the pin with a voltmeter/oscilloscope to see if it's really always high, maybe you've got the wrong pin in the rust code
<dirbaio[m]>
or the connetion is flaky
<slabity[m]>
Yea, I don't have an oscilloscope. I don't even have a debugger (hence why printing over USB debugging)
<JamesMunns[m]>
if you can, buy a couple rpi picos, they can be both!
<slabity[m]>
Okay, so it looks like `use_alert_rdy_pin_as_ready` is either bugged or not what I expect. The `ads1x1x` documentation says it should "provides a continuous-conversion ready pulse when in continuous-conversion mode." but it explicitly sets the `COMP_QUE` bits to `0b11` which according to the TI documentation says:
<slabity[m]>
"Set the COMP_QUE[1:0] bits to any 2-bit value other than 11 to keep the ALERT/RDY pin enabled, and allow the conversion ready signal to appear at the ALERT/RDY pin output."
<slabity[m]>
Maybe I'm completely reading this wrong. The Adafruit ADS1x1x sets those bits to 0b00 which apparently makes it emit a pulse
<slabity[m]>
So I have no idea if it's a bug, documentation error, or I'm just misunderstanding completely
<slabity[m]>
Anyway, it looks like I can get what I need by immediately calling adc.set_comparator_queue(ads1x1x::ComparatorQueue::One) after calling use_alert_rdy_pin_as_ready() to actually cause the pulsing that I need
<slabity[m]>
<dirbaio[m]> "(btw, wait_for_low, wait_for..." <- If I wanted to set up an interrupt manually though (to kick this off as a separate task for some additional processing), any idea on how I should do that? Looks like the `gpio_async` example just uses the `await` in a loop
<slabity[m]>
Would I just spawn a new generic task and then continue to use the wait_for_* functions in a loop?
<dirbaio[m]>
why do you want to handle the interrupt manually?
<slabity[m]>
This project is 90% learning on my end. Mostly just out of curiosity
<slabity[m]>
Honestly I'm not entirely sure how my current program is using interrupts for the USB logger. I see that I have `USBCTRL_IRQ => usb::InterruptHandler<USB>;` and I pass that `Irqs` struct to the USB driver. Not really sure how `embassy_usb_logger::run!` is using that driver when I print things out.
<dirbaio[m]>
to do it manually, you'd handle the interrupt with #[interrupt] from cortex-m-rt, and then use the PAC to do raw register writes to set up the interrupt to be triggered
<dirbaio[m]>
(the HAL's GPIO API doesn't have high-level functions to do interrupts manually, the supported way is async only)
<slabity[m]>
Ah, makes sense then
<dirbaio[m]>
what bind_interrupts! does is delegate handling an interrupt to the HAL
<dirbaio[m]>
it's the same as with gpio
<dirbaio[m]>
the HAL manages the raw register access and the interrupts for you. when you do something that requires waiting (for example wait_for_low().await) it tells the hardware to fire that irq when done, and puts the task to sleep
<dirbaio[m]>
when the irq fires, it wakes up the task
<dirbaio[m]>
and the executor manages the tasks, keeping track of which ones want to run or are sleeping, and putting the entire core to sleep if no task wants to run right now
<dirbaio[m]>
so you still have the option to handle interrupts manually, but it's not the "main" way supported by the HAL
<slabity[m]>
I'm guessing it takes advantage of the RP2040's 2-core design?
<slabity[m]>
In this particular case
<slabity[m]>
Or is it basically a state machine running on a single core?
<dirbaio[m]>
(or not, and run blocking code only in the 2nd core. or on the 1st core only, etc.)
<slabity[m]>
Yea, since the ads1x1x crate doesn't appear to support async then I can throw all that onto the second core
<slabity[m]>
Thanks for your help. I think I got more than enough information to keep myself busy for a while. I submitted a bug to the ads1x1x crate, but I might have just completely misunderstood what the intention behind the function was
IlPalazzo-ojiis1 has quit [Remote host closed the connection]
bomb has quit [Quit: 💣]
<slabity[m]>
One more thing I've noticed. It looks like embassy_usb_logger is munging some printed lines over the serial port with regular consistency. The consistency changes depending on how large of a buffer I pass into it is. It looks like it's cutting off the log prints at the buffer line..? Is that expected/can that be fixed?
<dirbaio[m]>
it drops data if the buffer is full
<slabity[m]>
So is it because I'm filling up the buffer too quickly?
<dirbaio[m]>
(it has to, if it blocked instead it'd cause a deadlock because blocking in whatever random piece of code that is printing could cause USB to stop transferring data. it could even be a log print in the USB driver itself even)
<dirbaio[m]>
recommended solution is to get a debug probe and use defmt instead
<slabity[m]>
And the non-recommended solution would be to just increase the buffer size to prevent that from happening?
<dirbaio[m]>
yes, or print less / slower
<slabity[m]>
Hmm... I'm printing around ~7146 bytes per second. With a buffer of 8192 bytes I am still getting overflows/cutoffs. How often does it flush out its buffer?
<dirbaio[m]>
every time you let the usb task run
<dirbaio[m]>
ie every time your task is waiting in an .await
<dirbaio[m]>
so doing long blocking things can impact throughput
<dirbaio[m]>
are you building with --release?
<slabity[m]>
Yes
<slabity[m]>
And I have the wait_for_falling_edge().await as well which should be getting called ~860 times per second (if the sample rate is accurate). Only blocking thing I can think of is the i2c read on the ADC, but I would be surprised if that took a significant amount of time.
<slabity[m]>
Looks like I'm getting ~794 i2c reads per second
<dirbaio[m]>
yeah, it's odd. feels like it should be possible to get it to go faster
<slabity[m]>
I feel like I should not be filling up the buffer that quickly
<dirbaio[m]>
could be pure CPU usage too. log uses std::fmt to format strings which is quite slow
<dirbaio[m]>
I insist, you'll have an easier time using a debug probe and defmt
<dirbaio[m]>
logging over USB is suboptimal for many reasons
<slabity[m]>
I have ordered a few more pico boards.
<slabity[m]>
But you know, logistics and shipping and all that. I promise I'll switch to a proper debugger once I get those all set.
<slabity[m]>
But even then, it should be clearing out the buffer ~800 per second. I don't understand why I still get overflows with an 8Kb buffer.
<dirbaio[m]>
yeah
<slabity[m]>
If I'm only printing ~8Kb per second anyways
<dirbaio[m]>
to test raw throughput you can try loop { info!("boo"); embassy_futures::yield_now().await; }
<dirbaio[m]>
(yield_now to let the usb task run)
<dirbaio[m]>
it could still be CPU usage tho. printing nombers is slower than a constant string for example
<dirbaio[m]>
and floats/doubles are super slow in the rp2040 because it has no FPU
<slabity[m]>
Thankfully no floats. All i16 values
<dirbaio[m]>
with rp2040 usb i've seen many hundreds of kb/s. but that's using usb directly, not going through log of course...