<Ecco>
Another question about SpiDevice: as a device driver, I want to implement a function that looks kind of like "fn send_n_packets(n: u8)", where the n packets have to be sent in a single CS transaction
<Ecco>
How can I do that? If my code calls "self.spi.transaction()" n times, then I get n CS transitions
<Ecco>
I want CS to go active, perform n writes, and then have CS go inactive
<Ecco>
I *could* achieve that by dynamically allocating an array of size n, and then doing a single "self.spi.transaction", but really I don't want to do dynamic memory allocation. And actually I don't want to allocate any memory, I just want to send the data as I compute it
<dirbaio[m]>
you have to do one transaction, yes
<dirbaio[m]>
if you want to avoid dynamic allocation, you can use a heapless::Vec of operations
<dirbaio[m]>
that means you have to set a maximum size
<Ecco>
well, yes, but even with healpess I'd be allocating memory
<Ecco>
let's say I want to send the bytes [1,2,3,4,....,n]
<dirbaio[m]>
how big is n in the worst case?
<Ecco>
I really don't want to allocate and fill that
<Ecco>
well, pretty big actually
<Ecco>
Big enough that it'd be a problem
<dirbaio[m]>
I see
<Ecco>
I'm writing a driver to send pixel data to a screen
<Ecco>
this is the "send_pixels" command
<Ecco>
potentially, the input can be large
<Ecco>
(the pixel data need to be massaged a certain way)
<dirbaio[m]>
screens typically allow toggling CS any time
<Ecco>
Well, any device should indeed
<Ecco>
but for some reason the datasheet on this one seems to use CS as a "start of transmission" marker
<dirbaio[m]>
:S
<dirbaio[m]>
well
<dirbaio[m]>
if you can't split the transaction in smaller transactions, and you don't want to buffer
<dirbaio[m]>
then you have to use SpiBus+OutputPin, you can't use SpiDevice
<Ecco>
fair enough
<dirbaio[m]>
SpiDevice doesn't allow computing the data as you send it like that
<dirbaio[m]>
the downside is your driver won't allow sharing the bus
<Ecco>
Is this an oversight, or is this fundamentally incompatible with the SpiDevice model?
<dirbaio[m]>
this was discussed a lot when designing SpiDevice
<dirbaio[m]>
there was an alternate SpiDevice design which did allow generating data on the fly, with a closure
<Ecco>
Because I mean, technically this screen *can* share the SPI bus. But once you start talking to it, (I think) you're supposed to send the whole commands at once
<dirbaio[m]>
it was decided to go with the current design because
<Ecco>
(I actually kind of looked for such a discussion online but didn't find it)
<dirbaio[m]>
- some platforms (Linux, some RTOSs) can't run arbitrary code within a transaction, you have to supply all the buffers upfront
<dirbaio[m]>
- it doesn't work with `dyn`
<dirbaio[m]>
- it doesn't work well with async
<Ecco>
oh
<dirbaio[m]>
* design because the closure-based API
<dirbaio[m]>
* design because the closure-based API had these issuse:
<dirbaio[m]>
* design because the closure-based API had these issues:
<dirbaio[m]>
the tradeoff is things like "big transaction generating data on-the-fly" is not supported anymore
<dirbaio[m]>
but
<dirbaio[m]>
with SpiBus you can still share the bus, you just have to do it "manually". your driver can take a `&RefCell<SpiBus>`
<dirbaio[m]>
and you can even share it between your "manual" sharing and other drivers that do use SpiDevice with RefCellDevice
<dirbaio[m]>
* with RefCellDevice, just share the refcell
<Ecco>
oh, ok
<dirbaio[m]>
so interoperability/sharing is not impossible, just harder
<dirbaio[m]>
it's unfortunate yep
<Ecco>
well, at least I know it's not just me misunderstanding something simple :)
<dirbaio[m]>
but the other alternative (the closure API) seems more unfortunate so...
<Ecco>
and this got me wondering (stupid question incoming)
<Ecco>
what are "transactions" anyway?
<Ecco>
I tried looking at the code in embedded-hal
<Ecco>
and… I just didn't get it
<Ecco>
it doesn't seem to be defined in embedded-hal, is it?
<dirbaio[m]>
a SPI transaction is "put CS low, do some data transfers, put CS high"
<Ecco>
But apparently there are multiple implementations
<Ecco>
I mean, as a driver author, I would not mind having to call "put CS low" and "put CS high" manually
<Ecco>
which is what I'll do with SpiBus+OutputPin anyway
<dirbaio[m]>
the multiple implementations are for different "kinds of mutexes" for sharing the bus (refcell, critical-section, std mutex..)
<dirbaio[m]>
but they all do the same
<dirbaio[m]>
lock the bus (with whatever mutex kind), set CS low, do transfers, set CS high, unlock bus
<Ecco>
makes perfect sense
<Ecco>
but then, as a driver author, I would not mind having to do this myself
<Ecco>
sure, a "transaction" method is convenient
<Ecco>
but if it doesn't work, I would not mind having to do it manually
<Ecco>
is it possible at all?
<dirbaio[m]>
yes, using SpiBus + OutputPin
<dirbaio[m]>
like in e-h 0.2
<Ecco>
but then how do I play well with another driver that uses SpiDevice?
<dirbaio[m]>
depends on how far you want to go
<dirbaio[m]>
the easiest way is to make your driver take `&RefCell<SpiBus>` and an `OutputPin` for example
<dirbaio[m]>
but then it'll work with RefCellDevice only (you're hardcoding the mutex kind), and you're paying the overhead of the RefCell even if you don't want sharing
<dirbaio[m]>
the more complete way would be to write your own "Interface" trait
<Ecco>
hmm, I think I'm starting to understand
<dirbaio[m]>
and make implementations of it that take either `SpiBus` (no sharing), `&RefCell<SpiBus>`, `&critical_section::Mutex<RefCell<SpiBus>>`
<dirbaio[m]>
it's kiiiiinda making your own custom SpiDevice
<Ecco>
Yeah, I see
<Ecco>
As a start I think I'm just going to use an SpiBus
<Ecco>
and, well, don't allow sharing
<Ecco>
I think it's rather common for displays to be alone on their bus
<Ecco>
At least it'll keep the code simple
jacobrosenthal[m has quit [Quit: Idle timeout reached: 172800s]
<Ecco>
Thanks for the help!
IlPalazzo-ojiisa has quit [Quit: Leaving.]
starblue has quit [Ping timeout: 260 seconds]
starblue has joined #rust-embedded
PhilMarkgraf[m] has joined #rust-embedded
<PhilMarkgraf[m]>
I've made a program that dumps a bunch of data with rprintln!() statements. I usually run something like this with "cargo embed", which opens its own local terminal. How can I capture this output into a file?
<GrantM11235[m]>
<Ecco> "this is the "send_pixels..." <- Can you split it up in to several batches of pixels? Like do a transaction with the command opcode and a few hundred pixels, then another transaction with the command opcode again and more pixels, etc
jiande2020 has joined #rust-embedded
korken89[m] has quit [Quit: Idle timeout reached: 172800s]
starblue has quit [Ping timeout: 260 seconds]
IlPalazzo-ojiisa has joined #rust-embedded
starblue has joined #rust-embedded
braincode[m] has quit [Quit: Idle timeout reached: 172800s]
jiande20201 has joined #rust-embedded
jiande2020 has quit [Ping timeout: 260 seconds]
jiande20201 is now known as jiande2020
IlPalazzo-ojiisa has quit [Remote host closed the connection]
mgudel[m] has quit [Quit: Idle timeout reached: 172800s]
<Ecco>
GrantM11235[m]: Indeed that's possible. It's sub-optimal, but possible indeed
albus_dandelion[ has joined #rust-embedded
<albus_dandelion[>
Hello, everyone! Is there a way to use ssd1306 screen on Linux? Like, connect screen to a raspberry pi and from raspberry pi just execute a program in Rust. I tried with this[https://crates.io/crates/ssd1306] crate, but idk, it needs some trait from embedded-hal to be implemented.
<albus_dandelion[>
Yes, I found that. But it's not working
<dirbaio[m]>
linux-embedded-hal 0.4 implements the traits from embedded-hal 1.0
<dirbaio[m]>
while it seems ssd1306 is expecting the i2c trait from embedded-hal 0.2
<albus_dandelion[>
sheeesh
<albus_dandelion[>
thank you
<albus_dandelion[>
i will try to find right version
<dirbaio[m]>
linux-embedded-hal 0.3 implements embedded-hal 0.2, so that should work
<dirbaio[m]>
or you could check if there's a new version of ssd1306 (or maybe display-interface-i2c?) that uses embedded-hal-1.0
<dirbaio[m]>
or if no one has done it yet and you feel adventurous, update it yourself and submit a pull request 🙃
<albus_dandelion[>
nowaying, changing version of `linux-embedded-hal` actually worked first try, thank you very much. I will also look at the `display-interface-i2c`
<albus_dandelion[>
I'm adventurous, but not very much knowing, about embedded programming and i2c interface
<albus_dandelion[>
s/,//
therealprof[m] has joined #rust-embedded
<therealprof[m]>
@albus_dandelion:inex.rocks I think a couple of people used SSD1306 with a RPi before in real projects but I couldn't find any in a jiffy. What I did find though is https://github.com/golemparts/rppal/tree/master . I can't judge the quality but there're I2C examples so it might be rather easy to cobble something together from the SSD1306 examples and that.
<therealprof[m]>
@albus_dandelion:inex.rocks Maybe checkout out #rust-embedded-graphics:matrix.org and ask there, too. There're many people there which might have done something like that before.
<dirbaio[m]>
huh what's the difference between rppal and linux-embedded-hal?
<dirbaio[m]>
seems i2c uses the ioctl kernel api so it'd work on any linux, not just rpis?
<dirbaio[m]>
for gpio it seems rppal does have a backend that pokes bcm regs directly
<therealprof[m]>
dirbaio[m]: Beats me, but they do have example code which might be a great help for beginners.
<albus_dandelion[>
Thank you, therealprof! I am begginer, so, should be useful
<therealprof[m]>
The documentation is also not bad. As the name implies it is very RPi centric, compared to `linux-embedded-hal` which should work on any system which exposes peripherals using kernel drivers.