diff --git a/sw/device/sca/aes_serial.c b/sw/device/sca/aes_serial.c
index 4cdf2988fc42e..26c215a267bb9 100644
--- a/sw/device/sca/aes_serial.c
+++ b/sw/device/sca/aes_serial.c
@@ -245,7 +245,7 @@ static void aes_encrypt(const uint8_t *plaintext, size_t plaintext_len) {
   // Using the SecAesStartTriggerDelay hardware parameter, the AES unit is
   // configured to start operation 40 cycles after receiving the start trigger.
   // This allows Ibex to go to sleep in order to not disturb the capture.
-  sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles);
+  sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, false);
 }
 
 /**
diff --git a/sw/device/sca/kmac_serial.c b/sw/device/sca/kmac_serial.c
index ad774a16bca19..239e12b932fe2 100644
--- a/sw/device/sca/kmac_serial.c
+++ b/sw/device/sca/kmac_serial.c
@@ -480,7 +480,7 @@ static void sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
   // configured to start operation 40 cycles after receiving the START and PROC
   // commands. This allows Ibex to go to sleep in order to not disturb the
   // capture.
-  sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles);
+  sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles, false);
 }
 
 /**
diff --git a/sw/device/sca/lib/sca.c b/sw/device/sca/lib/sca.c
index fe062b6e9d9fa..290422f9daeb9 100644
--- a/sw/device/sca/lib/sca.c
+++ b/sw/device/sca/lib/sca.c
@@ -309,7 +309,8 @@ void sca_set_trigger_low(void) {
   OT_DISCARD(dif_gpio_write(&gpio, trigger_bit_index, false));
 }
 
-void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles) {
+void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles,
+                        bool sw_trigger) {
   // Disable the IO_DIV4_PERI clock to reduce noise during the actual capture.
   // This also disables the UART(s) and GPIO modules required for
   // communication with the scope. Therefore, it has to be re-enabled after
@@ -328,8 +329,16 @@ void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles) {
   OT_DISCARD(dif_rv_timer_counter_set_enabled(&timer, kRvTimerHart,
                                               kDifToggleEnabled));
 
+  if (sw_trigger) {
+    sca_set_trigger_high();
+  }
+
   callee();
 
+  if (sw_trigger) {
+    sca_set_trigger_low();
+  }
+
   wait_for_interrupt();
 
   // Re-enable IO_DIV4_PERI clock to resume communication with the scope.
diff --git a/sw/device/sca/lib/sca.h b/sw/device/sca/lib/sca.h
index 19bfcfc54d1e8..c102b6002fdff 100644
--- a/sw/device/sca/lib/sca.h
+++ b/sw/device/sca/lib/sca.h
@@ -196,8 +196,10 @@ typedef void (*sca_callee)(void);
  *
  * @param callee Function to call before putting Ibex to sleep.
  * @param sleep_cycles Number of cycles to sleep.
+ * @param sw_trigger Raise trigger before calling the target function.
  */
-void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles);
+void sca_call_and_sleep(sca_callee callee, uint32_t sleep_cycles,
+                        bool sw_trigger);
 
 /**
  * Seeds the software LFSR usable e.g. for key masking.
diff --git a/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c b/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c
index 1e84dc59d4886..bd26fa4e80fda 100644
--- a/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c
+++ b/sw/device/sca/otbn_vertical/ecc256_keygen_serial.c
@@ -204,7 +204,7 @@ static void p256_run_keygen(uint32_t mode, const uint32_t *share0,
 
   // Execute program.
   sca_set_trigger_high();
-  sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles);
+  sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false);
   SS_CHECK_STATUS_OK(otbn_busy_wait_for_done());
   sca_set_trigger_low();
 }
diff --git a/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c b/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c
index ea255260c4ce7..05f051e60de46 100644
--- a/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c
+++ b/sw/device/sca/otbn_vertical/ecc256_modinv_serial.c
@@ -92,7 +92,7 @@ static void p256_run_modinv(uint32_t *k0, uint32_t *k1) {
 
   // Execute program.
   sca_set_trigger_high();
-  sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles);
+  sca_call_and_sleep(otbn_manual_trigger, kIbexOtbnSleepCycles, false);
   otbn_busy_wait_for_done();
   sca_set_trigger_low();
 }
diff --git a/sw/device/sca/sha3_serial.c b/sw/device/sca/sha3_serial.c
index da7a5c59af38d..cbeb1836ed286 100644
--- a/sw/device/sca/sha3_serial.c
+++ b/sw/device/sca/sha3_serial.c
@@ -405,9 +405,7 @@ static void sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
   // configured to start operation 40 cycles after receiving the START and PROC
   // commands. This allows Ibex to go to sleep in order to not disturb the
   // capture.
-  sca_set_trigger_high();
-  sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles);
-  sca_set_trigger_low();
+  sca_call_and_sleep(kmac_msg_proc, kIbexSha3SleepCycles, true);
 }
 
 /**
diff --git a/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c b/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c
index 223290c47442c..b78ddd2510f94 100644
--- a/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c
+++ b/sw/device/tests/crypto/cryptotest/firmware/aes_sca.c
@@ -19,6 +19,11 @@
 
 #include "hw/top_earlgrey/sw/autogen/top_earlgrey.h"
 
+/**
+ * Enable FPGA mode.
+ */
+static bool fpga_mode = false;
+
 enum {
   kAesKeyLengthMax = 32,
   kAesKeyLength = 16,
@@ -238,7 +243,15 @@ static aes_sca_error_t aes_encrypt(const uint8_t *plaintext,
   }
 
   // Start AES operation (this triggers the capture) and go to sleep.
-  sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles);
+  if (fpga_mode) {
+    // On the FPGA, the AES block automatically sets and unsets the trigger.
+    sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, false);
+  } else {
+    // On the chip, we need to manually set and unset the trigger. This is done
+    // in this function to have the trigger as close as possible to the AES
+    // operation.
+    sca_call_and_sleep(aes_manual_trigger, kIbexAesSleepCycles, true);
+  }
   return aesScaOk;
 }
 
@@ -302,11 +315,15 @@ status_t handle_aes_sca_single_encrypt(ujson_t *uj) {
     block_ctr = 1;
   }
 
-  sca_set_trigger_high();
+  if (fpga_mode) {
+    sca_set_trigger_high();
+  }
   if (aes_encrypt(uj_data.text, uj_data.text_length) != aesScaOk) {
     return ABORTED();
   }
-  sca_set_trigger_low();
+  if (fpga_mode) {
+    sca_set_trigger_low();
+  }
 
   TRY(aes_send_ciphertext(false, uj));
   return OK_STATUS(0);
@@ -391,14 +408,18 @@ status_t handle_aes_sca_batch_encrypt(ujson_t *uj) {
     block_ctr = num_encryptions;
   }
 
-  sca_set_trigger_high();
+  if (fpga_mode) {
+    sca_set_trigger_high();
+  }
   for (uint32_t i = 0; i < num_encryptions; ++i) {
     if (aes_encrypt(plaintext_random, kAesTextLength) != aesScaOk) {
       return ABORTED();
     }
     aes_serial_advance_random();
   }
-  sca_set_trigger_low();
+  if (fpga_mode) {
+    sca_set_trigger_low();
+  }
 
   TRY(aes_send_ciphertext(true, uj));
 
@@ -451,7 +472,9 @@ status_t handle_aes_sca_batch_alternative_encrypt(ujson_t *uj) {
   // Set trigger high outside of loop
   // On FPGA, the trigger is AND-ed with AES !IDLE and creates a LO-HI-LO per
   // AES operation
-  sca_set_trigger_high();
+  if (fpga_mode) {
+    sca_set_trigger_high();
+  }
   dif_aes_data_t ciphertext;
   for (uint32_t i = 0; i < num_encryptions; ++i) {
     // Encrypt
@@ -472,7 +495,9 @@ status_t handle_aes_sca_batch_alternative_encrypt(ujson_t *uj) {
     // Use ciphertext as next plaintext (incl. next call to this function)
     memcpy(batch_plaintext, ciphertext.data, kAesTextLength);
   }
-  sca_set_trigger_low();
+  if (fpga_mode) {
+    sca_set_trigger_low();
+  }
 
   // send last ciphertext
   cryptotest_aes_sca_ciphertext_t uj_output;
@@ -642,7 +667,9 @@ status_t handle_aes_sca_fvsr_key_batch_encrypt(ujson_t *uj) {
     return OUT_OF_RANGE();
   }
 
-  sca_set_trigger_high();
+  if (fpga_mode) {
+    sca_set_trigger_high();
+  }
   for (uint32_t i = 0; i < num_encryptions; ++i) {
     if (aes_key_mask_and_config(batch_keys[i], kAesKeyLength) != aesScaOk) {
       return ABORTED();
@@ -651,7 +678,9 @@ status_t handle_aes_sca_fvsr_key_batch_encrypt(ujson_t *uj) {
       return ABORTED();
     }
   }
-  sca_set_trigger_low();
+  if (fpga_mode) {
+    sca_set_trigger_low();
+  }
 
   TRY(aes_send_ciphertext(false, uj));
 
@@ -709,12 +738,16 @@ status_t handle_aes_sca_fvsr_data_batch_encrypt(ujson_t *uj) {
     sample_fixed = sca_next_lfsr(1, kScaLfsrOrder) & 0x1;
   }
 
-  sca_set_trigger_high();
+  if (fpga_mode) {
+    sca_set_trigger_high();
+  }
   for (uint32_t i = 0; i < num_encryptions; ++i) {
     aes_key_mask_and_config(batch_keys[i], kAesKeyLength);
     aes_encrypt(batch_plaintexts[i], kAesTextLength);
   }
-  sca_set_trigger_low();
+  if (fpga_mode) {
+    sca_set_trigger_low();
+  }
 
   TRY(aes_send_ciphertext(false, uj));
 
@@ -843,6 +876,12 @@ status_t handle_aes_sca_fvsr_key_start_batch_generate(ujson_t *uj) {
  * @param uj The received uJSON data.
  */
 status_t handle_aes_sca_init(ujson_t *uj) {
+  // Read mode. FPGA or discrete.
+  cryptotest_aes_sca_fpga_mode_t uj_data;
+  TRY(ujson_deserialize_cryptotest_aes_sca_fpga_mode_t(uj, &uj_data));
+  if (uj_data.fpga_mode == 0x01) {
+    fpga_mode = true;
+  }
   sca_init(kScaTriggerSourceAes, kScaPeripheralIoDiv4 | kScaPeripheralAes);
 
   if (dif_aes_init(mmio_region_from_addr(TOP_EARLGREY_AES_BASE_ADDR), &aes) !=
diff --git a/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c b/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c
index c65d7a5410dc6..5831cd7bbfe3f 100644
--- a/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c
+++ b/sw/device/tests/crypto/cryptotest/firmware/kmac_sca.c
@@ -542,7 +542,8 @@ static kmac_sca_error_t sha3_ujson_absorb(const uint8_t *msg, size_t msg_len) {
   if (fpga_mode == false) {
     // Start command. On the chip, we need to first issue a START command
     // before writing to the message FIFO.
-    sca_call_and_sleep(kmac_start_cmd, kIbexLoadHashPrefixKeySleepCycles);
+    sca_call_and_sleep(kmac_start_cmd, kIbexLoadHashPrefixKeySleepCycles,
+                       false);
   }
 
   // Write data to message FIFO.
@@ -556,11 +557,12 @@ static kmac_sca_error_t sha3_ujson_absorb(const uint8_t *msg, size_t msg_len) {
     // configured to start operation 320 cycles after receiving the START and
     // PROC commands. This allows Ibex to go to sleep in order to not disturb
     // the capture.
-    sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles);
+    sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles, false);
   } else {
     // On the chip, issue a PROCESS command to start operation and put Ibex
     // into sleep.
-    sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles);
+    sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles,
+                       false);
   }
 
   return kmacScaOk;
diff --git a/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c b/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c
index 3a8f3961bb177..2181759442fa4 100644
--- a/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c
+++ b/sw/device/tests/crypto/cryptotest/firmware/sha3_sca.c
@@ -418,15 +418,11 @@ sha3_sca_error_t sha3_serial_absorb(const uint8_t *msg, size_t msg_len) {
     // configured to start operation 320 cycles after receiving the START and
     // PROC commands. This allows Ibex to go to sleep in order to not disturb
     // the capture.
-    sca_set_trigger_high();
-    sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles);
-    sca_set_trigger_low();
+    sca_call_and_sleep(kmac_start_process_cmd, kIbexSha3SleepCycles, true);
   } else {
     // On the chip, issue a PROCESS command to start operation and put Ibex
     // into sleep.
-    sca_set_trigger_high();
-    sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles);
-    sca_set_trigger_low();
+    sca_call_and_sleep(kmac_process_cmd, kIbexLoadHashMessageSleepCycles, true);
   }
 
   return sha3ScaOk;
diff --git a/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h b/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h
index 6067d60903714..a891a68100181 100644
--- a/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h
+++ b/sw/device/tests/crypto/cryptotest/json/aes_sca_commands.h
@@ -56,6 +56,10 @@ UJSON_SERDE_STRUCT(CryptotestAesScaLfsr, cryptotest_aes_sca_lfsr_t, AES_SCA_LFSR
     field(ciphertext, uint8_t, AESSCA_CMD_MAX_MSG_BYTES) \
     field(ciphertext_length, uint32_t)
 UJSON_SERDE_STRUCT(CryptotestAesScaCiphertext, cryptotest_aes_sca_ciphertext_t, AES_SCA_CIPHERTEXT);
+
+#define AES_SCA_FPGA_MODE(field, string) \
+    field(fpga_mode, uint8_t)
+UJSON_SERDE_STRUCT(CryptotestAesScaFpgaMode, cryptotest_aes_sca_fpga_mode_t, AES_SCA_FPGA_MODE);
 // clang-format on
 
 #ifdef __cplusplus