diff --git a/CHANGELOG.md b/CHANGELOG.md
index e1d14b27..b29d00b0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,8 +18,20 @@ will consitute of a breaking change warranting a new major release:
 
 # [v6.0.0] to be released
 
+- `q7s-package` version v3.2.0
 - Important bugfixes for PTME. See `q7s-package` CHANGELOG.
 
+## Changed
+
+- Added back PTME busy bit polling. This is necessary due to changes to the AXI APB interface
+  to the PTME core.
+
+## Fixed
+
+- For the live channel (VC0), telemetry was still only dumped if the transmitter is active.
+  Please note that this fix will lead to crashes for FW versions below v3.2.
+  However, it might not be an issue for the oldest firmware on the satellite (v2.5.1).
+
 # [v5.2.0] 2023-07-02
 
 ## Fixed
diff --git a/CMakeLists.txt b/CMakeLists.txt
index b07423ac..3695c324 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,8 +9,8 @@
 # ##############################################################################
 cmake_minimum_required(VERSION 3.13)
 
-set(OBSW_VERSION_MAJOR 5)
-set(OBSW_VERSION_MINOR 2)
+set(OBSW_VERSION_MAJOR 6)
+set(OBSW_VERSION_MINOR 0)
 set(OBSW_VERSION_REVISION 0)
 
 # set(CMAKE_VERBOSE TRUE)
diff --git a/README.md b/README.md
index 6b06283c..ce57c33f 100644
--- a/README.md
+++ b/README.md
@@ -964,6 +964,12 @@ used by other software components to read the current chip and copy.
 This is a configuration scripts which runs after the Network Time Protocol has run. This script
 currently sets the static IP address `192.168.133.10` and starts the `can` interface.
 
+## Initial boot delay
+
+You can create a file named `boot_delays_secs.txt` inside the home folder to delay the OBSW boot
+for 6 seconds if the file is empty of for the number of seconds specified inside the file. This
+can be helpful if something inside the OBSW leads to an immediate crash of the OBC.
+
 ## PCDU
 
 Connect to serial console of P60 Dock
diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h
index 6a3e0d9e..146386c4 100644
--- a/bsp_q7s/boardconfig/busConf.h
+++ b/bsp_q7s/boardconfig/busConf.h
@@ -85,13 +85,9 @@ static constexpr char EN_RW_4[] = "enable_rw_4";
 static constexpr char RAD_SENSOR_CHIP_SELECT[] = "rad_sensor_chip_select";
 static constexpr char ENABLE_RADFET[] = "enable_radfet";
 
-static constexpr char PAPB_BUSY_SIGNAL_VC0[] = "papb_busy_signal_vc0";
 static constexpr char PAPB_EMPTY_SIGNAL_VC0[] = "papb_empty_signal_vc0";
-static constexpr char PAPB_BUSY_SIGNAL_VC1[] = "papb_busy_signal_vc1";
 static constexpr char PAPB_EMPTY_SIGNAL_VC1[] = "papb_empty_signal_vc1";
-static constexpr char PAPB_BUSY_SIGNAL_VC2[] = "papb_busy_signal_vc2";
 static constexpr char PAPB_EMPTY_SIGNAL_VC2[] = "papb_empty_signal_vc2";
-static constexpr char PAPB_BUSY_SIGNAL_VC3[] = "papb_busy_signal_vc3";
 static constexpr char PAPB_EMPTY_SIGNAL_VC3[] = "papb_empty_signal_vc3";
 
 static constexpr char PTME_RESETN[] = "ptme_resetn";
diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp
index 0e55661e..8223ceaf 100644
--- a/bsp_q7s/core/ObjectFactory.cpp
+++ b/bsp_q7s/core/ObjectFactory.cpp
@@ -731,20 +731,12 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
   // GPIO definitions of signals connected to the virtual channel interfaces of the PTME IP Core
   GpioCookie* gpioCookiePtmeIp = new GpioCookie;
   GpiodRegularByLineName* gpio = nullptr;
-  gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC0, "PAPB VC0");
-  gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_BUSY, gpio);
   gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC0, "PAPB VC0");
   gpioCookiePtmeIp->addGpio(gpioIds::VC0_PAPB_EMPTY, gpio);
-  gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC1, "PAPB VC1");
-  gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_BUSY, gpio);
   gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC1, "PAPB VC1");
   gpioCookiePtmeIp->addGpio(gpioIds::VC1_PAPB_EMPTY, gpio);
-  gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC2, "PAPB VC2");
-  gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_BUSY, gpio);
   gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC2, "PAPB VC2");
   gpioCookiePtmeIp->addGpio(gpioIds::VC2_PAPB_EMPTY, gpio);
-  gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_BUSY_SIGNAL_VC3, "PAPB VC3");
-  gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio);
   gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, "PAPB VC3");
   gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio);
   gpio = new GpiodRegularByLineName(q7s::gpioNames::PTME_RESETN, "PTME RESETN",
@@ -753,19 +745,14 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
   gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs");
 
   // Creating virtual channel interfaces
-  VirtualChannelIF* vc0 =
-      new PapbVcInterface(&args.gpioComIF, gpioIds::VC0_PAPB_BUSY, gpioIds::VC0_PAPB_EMPTY,
-                          q7s::UIO_PTME, q7s::uiomapids::PTME_VC0);
-  VirtualChannelIF* vc1 =
-      new PapbVcInterface(&args.gpioComIF, gpioIds::VC1_PAPB_BUSY, gpioIds::VC1_PAPB_EMPTY,
-                          q7s::UIO_PTME, q7s::uiomapids::PTME_VC1);
-  VirtualChannelIF* vc2 =
-      new PapbVcInterface(&args.gpioComIF, gpioIds::VC2_PAPB_BUSY, gpioIds::VC2_PAPB_EMPTY,
-                          q7s::UIO_PTME, q7s::uiomapids::PTME_VC2);
-  VirtualChannelIF* vc3 =
-      new PapbVcInterface(&args.gpioComIF, gpioIds::VC3_PAPB_BUSY, gpioIds::VC3_PAPB_EMPTY,
-                          q7s::UIO_PTME, q7s::uiomapids::PTME_VC3);
-
+  VirtualChannelIF* vc0 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC0_PAPB_EMPTY,
+                                              q7s::UIO_PTME, q7s::uiomapids::PTME_VC0);
+  VirtualChannelIF* vc1 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC1_PAPB_EMPTY,
+                                              q7s::UIO_PTME, q7s::uiomapids::PTME_VC1);
+  VirtualChannelIF* vc2 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC2_PAPB_EMPTY,
+                                              q7s::UIO_PTME, q7s::uiomapids::PTME_VC2);
+  VirtualChannelIF* vc3 = new PapbVcInterface(&args.gpioComIF, gpioIds::VC3_PAPB_EMPTY,
+                                              q7s::UIO_PTME, q7s::uiomapids::PTME_VC3);
   // Creating ptme object and adding virtual channel interfaces
   Ptme* ptme = new Ptme(objects::PTME);
   ptme->addVcInterface(ccsds::VC0, vc0);
diff --git a/common/config/devices/gpioIds.h b/common/config/devices/gpioIds.h
index ac193bd2..bed82142 100644
--- a/common/config/devices/gpioIds.h
+++ b/common/config/devices/gpioIds.h
@@ -96,13 +96,9 @@ enum gpioId_t {
 
   SPI_MUX,
   VC0_PAPB_EMPTY,
-  VC0_PAPB_BUSY,
   VC1_PAPB_EMPTY,
-  VC1_PAPB_BUSY,
   VC2_PAPB_EMPTY,
-  VC2_PAPB_BUSY,
   VC3_PAPB_EMPTY,
-  VC3_PAPB_BUSY,
   PTME_RESETN,
 
   PDEC_RESET,
diff --git a/linux/ipcore/PapbVcInterface.cpp b/linux/ipcore/PapbVcInterface.cpp
index 60968cc6..5dcb4519 100644
--- a/linux/ipcore/PapbVcInterface.cpp
+++ b/linux/ipcore/PapbVcInterface.cpp
@@ -7,20 +7,16 @@
 
 #include "fsfw/serviceinterface/ServiceInterface.h"
 
-PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId,
-                                 gpioId_t papbEmptyId, std::string uioFile, int mapNum)
-    : gpioComIF(gpioComIF),
-      papbBusyId(papbBusyId),
-      papbEmptyId(papbEmptyId),
-      uioFile(std::move(uioFile)),
-      mapNum(mapNum) {}
+PapbVcInterface::PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId,
+                                 std::string uioFile, int mapNum)
+    : gpioComIF(gpioComIF), papbEmptyId(papbEmptyId), uioFile(std::move(uioFile)), mapNum(mapNum) {}
 
 PapbVcInterface::~PapbVcInterface() {}
 
 ReturnValue_t PapbVcInterface::initialize() {
   UioMapper uioMapper(uioFile, mapNum);
   ReturnValue_t result = uioMapper.getMappedAdress(const_cast<uint32_t**>(&vcBaseReg),
-                                                   UioMapper::Permissions::WRITE_ONLY);
+                                                   UioMapper::Permissions::READ_WRITE);
   if (result != returnvalue::OK) {
     return result;
   }
@@ -32,63 +28,27 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
   if (size < 4) {
     return returnvalue::FAILED;
   }
-  if (pollInterfaceReadiness(0, true) == returnvalue::OK) {
+  if (pollReadyForPacket()) {
     startPacketTransfer(ByteWidthCfg::ONE);
   } else {
     return DirectTmSinkIF::IS_BUSY;
   }
-  // TODO: This should work but does not.. :(
-  //  size_t idx = 0;
-  //  while (idx < size) {
-  //
-  //    nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
-  //    if ((size - idx) < 4) {
-  //      *vcBaseReg = CONFIG_DATA_INPUT | (size - idx - 1);
-  //      usleep(1);
-  //    }
-  //    if (pollPapbBusySignal(2) == returnvalue::OK) {
-  //      //      vcBaseReg + DATA_REG_OFFSET + 3 = static_cast<uint8_t>(data + idx);
-  //      //      vcBaseReg + DATA_REG_OFFSET + 2 = static_cast<uint8_t>(data + idx + 1);
-  //      //      vcBaseReg + DATA_REG_OFFSET + 1 = static_cast<uint8_t>(data + idx + 2);
-  //      //      vcBaseReg + DATA_REG_OFFSET = static_cast<uint8_t>(data + idx + 3);
-  //
-  //      // std::memcpy((vcBaseReg + DATA_REG_OFFSET), data + idx , nextWriteSize);
-  //      *(vcBaseReg + DATA_REG_OFFSET) = *reinterpret_cast<const uint32_t*>(data + idx);
-  //      //uint8_t* byteReg = reinterpret_cast<uint8_t*>(vcBaseReg + DATA_REG_OFFSET);
-  //
-  //      //byteReg[0] = data[idx];
-  //      //byteReg[1] = data[idx];
-  //    } else {
-  //      abortPacketTransfer();
-  //      return returnvalue::FAILED;
-  //    }
-  //    // TODO: Change this after the bugfix. Right now, the PAPB ignores the content of the byte
-  //    // width configuration.5
-  //    // It's okay to increment by a larger amount for the last segment here, loop will be over
-  //    // in any case.
-  //    idx += 4;
-  //  }
-  for (size_t idx = 0; idx < size; idx++) {
-    // This delay is super-important, DO NOT REMOVE!
-    // Polling the GPIO or the config register too often messes up the scheduler.
-    // TODO: Maybe this should not be done like this. It would be better if there was a custom
-    // FPGA module which can accept packets and then takes care of dumping that packet into
-    // the PTME. DMA would be an ideal solution for this.
-    nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
-    if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
-      *(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
-    } else {
-      abortPacketTransfer();
-      return returnvalue::FAILED;
-    }
-  }
-  nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
-  if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
-    completePacketTransfer();
-  } else {
+  if (not pollReadyForOctet(MAX_BUSY_POLLS)) {
     abortPacketTransfer();
     return returnvalue::FAILED;
   }
+  for (size_t idx = 0; idx < size; idx++) {
+    if (not pollReadyForOctet(MAX_BUSY_POLLS)) {
+      abortPacketTransfer();
+      return returnvalue::FAILED;
+    }
+    *(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
+  }
+  if (not pollReadyForOctet(MAX_BUSY_POLLS)) {
+    abortPacketTransfer();
+    return returnvalue::FAILED;
+  }
+  completePacketTransfer();
   return returnvalue::OK;
 }
 
@@ -98,63 +58,49 @@ void PapbVcInterface::startPacketTransfer(ByteWidthCfg initWidth) {
 
 void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; }
 
-ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries,
-                                                      bool checkReadyState) const {
-  uint32_t busyIdx = 0;
-  nextDelay.tv_nsec = FIRST_DELAY_PAPB_POLLING_NS;
-
-  while (true) {
-    // Check if PAPB interface is ready to receive data. Use the configuration register for this.
-    // Bit 5, see PTME ptme_001_01-0-7-r2 Table 31.
-    uint32_t reg = *vcBaseReg;
-    bool busy = (reg >> 5) & 0b1;
-    bool ready = (reg >> 6) & 0b1;
-    if (not busy) {
-      return returnvalue::OK;
-    }
-    if (checkReadyState and not ready) {
-      return PAPB_BUSY;
-    }
-
-    busyIdx++;
-    if (busyIdx >= maxPollRetries) {
-      return PAPB_BUSY;
-    }
-
-    // Ignore signal handling here for now.
-    nanosleep(&nextDelay, &remDelay);
-    // Adaptive delay.
-    if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) {
-      nextDelay.tv_nsec *= 2;
-    }
-  }
-  return returnvalue::OK;
+bool PapbVcInterface::pollReadyForPacket() const {
+  //  Check if PAPB interface is ready to receive data. Use the configuration register for this.
+  //  Bit 5, see PTME ptme_001_01-0-7-r2 Table 31.
+  uint32_t reg = *vcBaseReg;
+  return (reg >> 6) & 0b1;
 }
 
-void PapbVcInterface::isVcInterfaceBufferEmpty() {
+bool PapbVcInterface::isVcInterfaceBufferEmpty() {
   ReturnValue_t result = returnvalue::OK;
   gpio::Levels papbEmptyState = gpio::Levels::HIGH;
 
   result = gpioComIF->readGpio(papbEmptyId, papbEmptyState);
 
   if (result != returnvalue::OK) {
-    sif::warning << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal"
-                 << std::endl;
-    return;
+    sif::error << "PapbVcInterface::isVcInterfaceBufferEmpty: Failed to read papb empty signal"
+               << std::endl;
+    return true;
   }
 
   if (papbEmptyState == gpio::Levels::HIGH) {
-    sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is empty" << std::endl;
-  } else {
-    sif::debug << "PapbVcInterface::isVcInterfaceBufferEmpty: Buffer is not empty" << std::endl;
+    return true;
   }
-  return;
+  return false;
 }
 
-bool PapbVcInterface::isBusy() const { return pollInterfaceReadiness(0, true) == PAPB_BUSY; }
+bool PapbVcInterface::isBusy() const { return not pollReadyForPacket(); }
 
 void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); }
 
+inline bool PapbVcInterface::pollReadyForOctet(uint32_t maxCycles) const {
+  uint32_t reg;
+  uint32_t idx = 0;
+  while (idx < maxCycles) {
+    reg = *vcBaseReg;
+    // Busy bit.
+    if (not((reg >> 5) & 0b1)) {
+      return true;
+    }
+    idx++;
+  }
+  return false;
+}
+
 ReturnValue_t PapbVcInterface::sendTestFrame() {
   /** Size of one complete transfer frame data field amounts to 1105 bytes */
   uint8_t testPacket[1105];
diff --git a/linux/ipcore/PapbVcInterface.h b/linux/ipcore/PapbVcInterface.h
index e54def5d..b5160748 100644
--- a/linux/ipcore/PapbVcInterface.h
+++ b/linux/ipcore/PapbVcInterface.h
@@ -30,8 +30,7 @@ class PapbVcInterface : public VirtualChannelIF {
    * @param uioFile       UIO file providing access to the PAPB bus
    * @param mapNum        Map number of UIO map associated with this virtual channel
    */
-  PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbBusyId, gpioId_t papbEmptyId,
-                  std::string uioFile, int mapNum);
+  PapbVcInterface(LinuxLibgpioIF* gpioComIF, gpioId_t papbEmptyId, std::string uioFile, int mapNum);
   virtual ~PapbVcInterface();
 
   bool isBusy() const override;
@@ -81,11 +80,9 @@ class PapbVcInterface : public VirtualChannelIF {
 
   static constexpr long int FIRST_DELAY_PAPB_POLLING_NS = 10;
   static constexpr long int MAX_DELAY_PAPB_POLLING_NS = 40;
+  static constexpr uint32_t MAX_BUSY_POLLS = 1000;
 
   LinuxLibgpioIF* gpioComIF = nullptr;
-
-  /** Pulled to low when virtual channel not ready to receive data */
-  gpioId_t papbBusyId = gpio::NO_GPIO;
   /** High when external buffer memory of virtual channel is empty */
   gpioId_t papbEmptyId = gpio::NO_GPIO;
 
@@ -120,13 +117,15 @@ class PapbVcInterface : public VirtualChannelIF {
    *
    * @return  returnvalue::OK when ready to receive data else PAPB_BUSY.
    */
-  inline ReturnValue_t pollInterfaceReadiness(uint32_t maxPollRetries, bool checkReadyState) const;
+  inline bool pollReadyForPacket() const;
+
+  inline bool pollReadyForOctet(uint32_t maxCycles) const;
 
   /**
    * @brief   This function can be used for debugging to check whether there are packets in
    *          the packet buffer of the virtual channel or not.
    */
-  void isVcInterfaceBufferEmpty();
+  bool isVcInterfaceBufferEmpty();
 
   /**
    * @brief   This function sends a complete telemetry transfer frame data field (1105 bytes)
diff --git a/mission/com/LiveTmTask.cpp b/mission/com/LiveTmTask.cpp
index d09c6ced..39648c15 100644
--- a/mission/com/LiveTmTask.cpp
+++ b/mission/com/LiveTmTask.cpp
@@ -19,13 +19,8 @@ LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunne
 ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) {
   readCommandQueue();
   while (true) {
-    bool performWriteOp = true;
-    if (mode == MODE_OFF or ptmeLocked) {
-      performWriteOp = false;
-    }
-
     // The funnel tasks are scheduled here directly as well.
-    ReturnValue_t result = channel.handleNextTm(performWriteOp);
+    ReturnValue_t result = channel.handleNextTm(!ptmeLocked);
     if (result == DirectTmSinkIF::IS_BUSY) {
       sif::error << "Lost live TM, PAPB busy" << std::endl;
     }
diff --git a/mission/com/PersistentLogTmStoreTask.cpp b/mission/com/PersistentLogTmStoreTask.cpp
index 77f2bb7d..28545457 100644
--- a/mission/com/PersistentLogTmStoreTask.cpp
+++ b/mission/com/PersistentLogTmStoreTask.cpp
@@ -42,13 +42,7 @@ ReturnValue_t PersistentLogTmStoreTask::performOperation(uint8_t opCode) {
     if (not someonesBusy) {
       TaskFactory::delayTask(100);
     } else if (vcBusyDuringDump) {
-      // TODO: Might not be necessary
-      sif::debug << "VC busy, delaying" << std::endl;
       TaskFactory::delayTask(10);
-    } else {
-      // TODO: Would be best to remove this, but not delaying here can lead to evil issues.
-      // Polling the PAPB of the PTME core too often leads to scheuduling issues.
-      TaskFactory::delayTask(2);
     }
   }
 }
diff --git a/mission/com/PersistentSingleTmStoreTask.cpp b/mission/com/PersistentSingleTmStoreTask.cpp
index 1b77365b..d6f43289 100644
--- a/mission/com/PersistentSingleTmStoreTask.cpp
+++ b/mission/com/PersistentSingleTmStoreTask.cpp
@@ -24,13 +24,7 @@ ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) {
     if (not busy) {
       TaskFactory::delayTask(100);
     } else if (dumpContext.vcBusyDuringDump) {
-      sif::debug << "VC busy, delaying" << std::endl;
-      // TODO: Might not be necessary
       TaskFactory::delayTask(10);
-    } else {
-      // TODO: Would be best to remove this, but not delaying here can lead to evil issues.
-      // Polling the PAPB of the PTME core too often leads to scheuduling issues.
-      TaskFactory::delayTask(2);
     }
   }
 }