diff --git a/controller/src/logic/mod.rs b/controller/src/logic/mod.rs
index 495518b337901a65d0997c6cb5dd13b235377ba8..82ed9c5dcf3cc236fd98234d2f0fadb110fd4d47 100644
--- a/controller/src/logic/mod.rs
+++ b/controller/src/logic/mod.rs
@@ -22,8 +22,6 @@ impl State {
     }
 }
 
-static mut STATE: Option<State> = None;
-
 #[allow(clippy::needless_pass_by_value, clippy::used_underscore_binding)] // Clippy bug
 pub fn start_i2c_target(
     spawner: Spawner,
@@ -32,22 +30,19 @@ pub fn start_i2c_target(
     encoders: Encoders<'static>,
     _wwdg: WWDG,
 ) {
-    unsafe {
-        STATE = Some(State::new(i2c2, encoders));
-    }
-    spawner.spawn(i2c_engine()).unwrap();
+    spawner.spawn(i2c_engine(i2c2, encoders)).unwrap();
     spawner.spawn(watchdog::watchdog()).unwrap();
     spawner.spawn(motor_control::motor_control(motors)).unwrap();
 }
 
 #[embassy_executor::task]
-async fn i2c_engine() {
-    I2C2::start(&i2c_callback).await;
+async fn i2c_engine(i2c2: I2C2, encoders: Encoders<'static>) {
+    let state = State::new(i2c2, encoders);
+    I2C2::start(&i2c_callback, state).await;
 }
 
-fn i2c_callback(command: &[u8], response: &mut Vec<u8, MESSAGE_SIZE>) {
+fn i2c_callback(command: &[u8], response: &mut Vec<u8, MESSAGE_SIZE>, state: &mut State) {
     #[allow(static_mut_refs)]
-    let state = unsafe { STATE.as_mut().unwrap() };
     if process_command(state, command, response) {
         watchdog::ping();
     } else {
diff --git a/i2c2-target/src/lib.rs b/i2c2-target/src/lib.rs
index 20e0fe4efc5264a06a3421c80b7118fb6f8fb1ba..9a48baa68ca8f61fc03186118031f34e7ce666f2 100644
--- a/i2c2-target/src/lib.rs
+++ b/i2c2-target/src/lib.rs
@@ -12,7 +12,7 @@ use heapless::Vec;
 
 pub const MESSAGE_SIZE: usize = 8;
 
-pub type Callback = &'static dyn Fn(&[u8], &mut Vec<u8, MESSAGE_SIZE>);
+pub type Callback<State> = &'static dyn Fn(&[u8], &mut Vec<u8, MESSAGE_SIZE>, &mut State);
 
 struct Format(Sr1);
 
@@ -89,7 +89,7 @@ impl I2C2 {
     }
 
     /// Start answering I²C requests using the provided callback.
-    pub async fn start(callback: Callback) {
+    pub async fn start<State>(callback: Callback<State>, mut state: State) {
         let mut incoming = [0u8; MESSAGE_SIZE];
         let mut outgoing: Vec<u8, MESSAGE_SIZE> = Vec::new();
         unsafe {
@@ -110,7 +110,7 @@ impl I2C2 {
                 let r = i2c_receive(&mut incoming).await;
                 outgoing.clear();
                 match r {
-                    Ok(incoming) => callback(incoming, &mut outgoing),
+                    Ok(incoming) => callback(incoming, &mut outgoing, &mut state),
                     Err(e) => {
                         defmt::warn!("error while receiving: {}", e);
                     }