Skip to content

interrupt design #3

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
oli-obk opened this issue Dec 13, 2016 · 2 comments
Open

interrupt design #3

oli-obk opened this issue Dec 13, 2016 · 2 comments

Comments

@oli-obk
Copy link
Member

oli-obk commented Dec 13, 2016

We definitely want to start using interrupts at some point. It's trivial to simply put a function into the interrupt table, but that function then has neither state nor a way to communicate with anything. I say we first figure out the way we want to use interrupts, and then solve how that can be done. So this issue is just here for the API.

Obviously closures come into mind when thinking about code that should be run when an interrupt triggers. There's several ways we could use them:

add a handler for the entire program lifetime

let a = some_owned_register;
interrupt_table.insert(id, move || a.update(|a| a.set_some_flag()));
// can never get `some_owned_register` back
// but could overwrite interrupt `id` with a new handler

add a handler that borrows parts of the surroundings

let a = &mut some_owned_register;
interrupt_table.with_interrupt(
    id,
    || a.update(|a| a.set_some_flag()),
    |interrupt_table| {
        // code that needs that interrupt to be set
    }
);
// interrupt is not set anymore, `some_owned_register` is available again

add a handler and a state object that you'll get back afterwards

interrupt_table.insert(id, some_owned_register, some_function_that_takes_a_ref_mut_register);
// code that needs that interrupt to be set
let some_owned_register = interrupt_table.remove(id).unwrap();
// got `some_owned_register` back

I don't think we need to decide on either of the three, they can work simultaneously.

Anything else in the possible design space?

@mbr
Copy link
Member

mbr commented Dec 13, 2016

One thing is to keep in mind that low-end MCUs may not have a reconfigurable interrupt table (I believe some Cortex-M0s fall into this category?).

What about good old static data? I've been meaning to look into that anyway, but here's how it would work in "conventional" languages:

  1. Have a static interrupt handler that is fixed that contains a fixed memory address for a peripheral.
  2. A global, mutable data structure (aka "static").
  3. Some sort of concurrency-safe way to access the data structure.

Let's assume that 2. is some sort of buffer, the interrupt handler receives data and puts it into said buffer and the main thread wants to read it periodically.

On first glance, this setup is fairly unsafe as the interrupt may fire before the buffer is initialized. In a real-world applications, this is often easily solved by not powering on the components that generate the interrupt before the buffer has been initialized. It would be good if we could express this constraint somehow, note that there may be different mechanisms at work here (not powering on vs masking the interrupts by default).

If we were to start using the static-buffer style of fixed interrupt handlers, we have to fix two issues: Not handling interrupts before we are ready to do so (i.e. the buffer has been initialized) and transferring ownership of resources into interrupt handlers.

Note that buffer initialization here can mean as little as ensuring that the buffer is properly zero'd first -- puting an Option<_> there makes it possible to have it simply start as None and go from there, at the cost of a runtime check each time the interrupt fires. Ownership of resources could be handled by Option<_> as well this way, but all this incurs a runtime cost.

We could also encode initialization state in the type system to varying degrees.

Alas, I need to read up more on how static data is handled first.

@oli-obk
Copy link
Member Author

oli-obk commented Dec 14, 2016

Right. So that is a fourth solution. We can probably wrap the first three solutions in a way that they can be applied on top of the fourth solution by making the static data a pointer to the closure. But yes, that will require some runtime cost like unwrapping.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants