diff --git a/platformio.ini b/platformio.ini
index 57b4be3fe..6c42ec407 100644
--- a/platformio.ini
+++ b/platformio.ini
@@ -66,7 +66,7 @@ lib_deps =
   Wire ; explicitly needed here because the AXP202 library forgets to add it
   https://github.com/meshtastic/arduino-fsm.git 
   https://github.com/meshtastic/SparkFun_Ublox_Arduino_Library.git
-  https://github.com/meshtastic/RadioLib.git#d6b12f7eb0a06bd2414c79b437b25d377e3f603f
+  https://github.com/meshtastic/RadioLib.git#7989a269be590a5d4914ac04069b58f4930c45c1
   https://github.com/meshtastic/TinyGPSPlus.git 
   https://github.com/meshtastic/AXP202X_Library.git#8404abb6d4b486748636bc6ad72d2a47baaf5460
 
diff --git a/src/SPILock.cpp b/src/SPILock.cpp
new file mode 100644
index 000000000..43d841fc8
--- /dev/null
+++ b/src/SPILock.cpp
@@ -0,0 +1,11 @@
+#include "SPILock.h"
+#include <Arduino.h>
+#include <assert.h>
+
+concurrency::Lock *spiLock;
+
+void initSPI()
+{
+    assert(!spiLock);
+    spiLock = new concurrency::Lock();
+}
\ No newline at end of file
diff --git a/src/SPILock.h b/src/SPILock.h
new file mode 100644
index 000000000..8a4bd5dbb
--- /dev/null
+++ b/src/SPILock.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "../concurrency/LockGuard.h"
+
+/**
+ * Used to provide mutual exclusion for access to the SPI bus.  Usage:
+ * concurrency::LockGuard g(spiLock);
+ */
+extern concurrency::Lock *spiLock;
+
+/** Setup SPI access and create the spiLock lock. */
+void initSPI();
\ No newline at end of file
diff --git a/src/graphics/TFT.cpp b/src/graphics/TFT.cpp
index ed3679908..dcaf53ec4 100644
--- a/src/graphics/TFT.cpp
+++ b/src/graphics/TFT.cpp
@@ -1,12 +1,13 @@
 #include "configuration.h"
 
 #ifdef ST7735_CS
+#include "SPILock.h"
 #include "TFT.h"
 #include "graphics/configs.h"
 #include <SPI.h>
 #include <TFT_eSPI.h> // Graphics and font library for ST7735 driver chip
 
-TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
+static TFT_eSPI tft = TFT_eSPI(); // Invoke library, pins defined in User_Setup.h
 
 TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
 {
@@ -17,6 +18,9 @@ TFTDisplay::TFTDisplay(uint8_t address, int sda, int scl)
 // Write the buffer to the display memory
 void TFTDisplay::display(void)
 {
+    concurrency::LockGuard g(spiLock);
+
+#if 1
     // FIXME - only draw bits have changed (use backbuf similar to the other displays)
     // tft.drawBitmap(0, 0, buffer, 128, 64, TFT_YELLOW, TFT_BLACK);
     for (uint8_t y = 0; y < SCREEN_HEIGHT; y++) {
@@ -28,6 +32,7 @@ void TFTDisplay::display(void)
             tft.drawPixel(x, y, isset ? TFT_WHITE : TFT_BLACK);
         }
     }
+#endif
 }
 
 // Send a command to the display (low level function)
@@ -47,10 +52,12 @@ bool TFTDisplay::connect()
     pinMode(ST7735_BACKLIGHT_EN, OUTPUT);
 #endif
 
+#if 1
     tft.init();
     tft.setRotation(3); // Orient horizontal and wide underneath the silkscreen name label
-    // tft.fillScreen(TFT_BLUE);
+    tft.fillScreen(TFT_BLACK);
     // tft.drawRect(0, 0, 40, 10, TFT_PURPLE); // wide rectangle in upper left
+#endif
 
     return true;
 }
diff --git a/src/graphics/TFT.h b/src/graphics/TFT.h
index eec6d07b5..83168e2e1 100644
--- a/src/graphics/TFT.h
+++ b/src/graphics/TFT.h
@@ -9,7 +9,8 @@
  * optimize display() to only draw changed pixels (see other OLED subclasses for examples)
  * implement displayOn/displayOff to turn off the TFT device (and backlight)
  * Use the fast NRF52 SPI API rather than the slow standard arduino version
- * turn radio back on
+ *
+ * turn radio back on - currently with both on spi bus is fucked? or are we leaving chip select asserted?
  */
 class TFTDisplay : public OLEDDisplay
 {
diff --git a/src/main.cpp b/src/main.cpp
index bd4bd079b..53780f6fb 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -34,6 +34,7 @@
 // #include "rom/rtc.h"
 #include "DSRRouter.h"
 // #include "debug.h"
+#include "SPILock.h"
 #include "graphics/Screen.h"
 #include "main.h"
 #include "sleep.h"
@@ -220,6 +221,16 @@ void setup()
     nrf52Setup();
 #endif
 
+    // Init our SPI controller (must be before screen and lora)
+    initSPI();
+#ifdef NRF52_SERIES
+    SPI.begin();
+#else
+    // ESP32
+    SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
+    SPI.setFrequency(4000000);
+#endif
+
     // Initialize the screen first so we can show the logo while we start up everything else.
 #ifdef ST7735_CS
     screen.setup();
@@ -278,15 +289,6 @@ void setup()
     digitalWrite(SX1262_ANT_SW, 1);
 #endif
 
-    // Init our SPI controller
-#ifdef NRF52_SERIES
-    SPI.begin();
-#else
-    // ESP32
-    SPI.begin(RF95_SCK, RF95_MISO, RF95_MOSI, RF95_NSS);
-    SPI.setFrequency(4000000);
-#endif
-
     // MUST BE AFTER service.init, so we have our radio config settings (from nodedb init)
     RadioInterface *rIf = NULL;
 
diff --git a/src/mesh/RadioLibInterface.cpp b/src/mesh/RadioLibInterface.cpp
index ae94231d2..30f7de50e 100644
--- a/src/mesh/RadioLibInterface.cpp
+++ b/src/mesh/RadioLibInterface.cpp
@@ -1,6 +1,7 @@
 #include "RadioLibInterface.h"
 #include "MeshTypes.h"
 #include "NodeDB.h"
+#include "SPILock.h"
 #include "mesh-pb-constants.h"
 #include <configuration.h>
 #include <pb_decode.h>
@@ -9,6 +10,13 @@
 // FIXME, we default to 4MHz SPI, SPI mode 0, check if the datasheet says it can really do that
 static SPISettings spiSettings(4000000, MSBFIRST, SPI_MODE0);
 
+void LockingModule::SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes)
+{
+    concurrency::LockGuard g(spiLock);
+
+    Module::SPItransfer(cmd, reg, dataOut, dataIn, numBytes);
+}
+
 RadioLibInterface::RadioLibInterface(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE busy,
                                      SPIClass &spi, PhysicalLayer *_iface)
     : concurrency::PeriodicTask(0), module(cs, irq, rst, busy, spi, spiSettings), iface(_iface)
@@ -126,6 +134,8 @@ bool RadioLibInterface::canSendImmediately()
 /// bluetooth comms code.  If the txmit queue is empty it might return an error
 ErrorCode RadioLibInterface::send(MeshPacket *p)
 {
+    // Sometimes when testing it is useful to be able to never turn on the xmitter
+#ifndef LORA_DISABLE_SENDING
     printPacket("enqueuing for send", p);
     DEBUG_MSG("txGood=%d,rxGood=%d,rxBad=%d\n", txGood, rxGood, rxBad);
     ErrorCode res = txQueue.enqueue(p, 0) ? ERRNO_OK : ERRNO_UNKNOWN;
@@ -140,6 +150,10 @@ ErrorCode RadioLibInterface::send(MeshPacket *p)
     startTransmitTimer(true);
 
     return res;
+#else
+    packetPool.release(p);
+    return ERRNO_UNKNOWN;
+#endif
 }
 
 bool RadioLibInterface::canSleep()
diff --git a/src/mesh/RadioLibInterface.h b/src/mesh/RadioLibInterface.h
index a19c47412..d393077b5 100644
--- a/src/mesh/RadioLibInterface.h
+++ b/src/mesh/RadioLibInterface.h
@@ -16,6 +16,49 @@
 #define INTERRUPT_ATTR
 #endif
 
+/**
+ * A wrapper for the RadioLib Module class, that adds mutex for SPI bus access
+ */
+class LockingModule : public Module
+{
+  public:
+    /*!
+      \brief Extended SPI-based module constructor.
+
+      \param cs Arduino pin to be used as chip select.
+
+      \param irq Arduino pin to be used as interrupt/GPIO.
+
+      \param rst Arduino pin to be used as hardware reset for the module.
+
+      \param gpio Arduino pin to be used as additional interrupt/GPIO.
+
+      \param spi SPI interface to be used, can also use software SPI implementations.
+
+      \param spiSettings SPI interface settings.
+    */
+    LockingModule(RADIOLIB_PIN_TYPE cs, RADIOLIB_PIN_TYPE irq, RADIOLIB_PIN_TYPE rst, RADIOLIB_PIN_TYPE gpio, SPIClass &spi,
+                  SPISettings spiSettings)
+        : Module(cs, irq, rst, gpio, spi, spiSettings)
+    {
+    }
+
+    /*!
+    \brief SPI single transfer method.
+
+    \param cmd SPI access command (read/write/burst/...).
+
+    \param reg Address of SPI register to transfer to/from.
+
+    \param dataOut Data that will be transfered from master to slave.
+
+    \param dataIn Data that was transfered from slave to master.
+
+    \param numBytes Number of bytes to transfer.
+    */
+    virtual void SPItransfer(uint8_t cmd, uint8_t reg, uint8_t *dataOut, uint8_t *dataIn, uint8_t numBytes);
+};
+
 class RadioLibInterface : public RadioInterface, private concurrency::PeriodicTask
 {
     /// Used as our notification from the ISR
@@ -49,7 +92,7 @@ class RadioLibInterface : public RadioInterface, private concurrency::PeriodicTa
     float currentLimit = 100;     // FIXME
     uint16_t preambleLength = 32; // 8 is default, but FIXME use longer to increase the amount of sleep time when receiving
 
-    Module module; // The HW interface to the radio
+    LockingModule module; // The HW interface to the radio
 
     /**
      * provides lowest common denominator RadioLib API
diff --git a/variants/lora_relay_v1/variant.h b/variants/lora_relay_v1/variant.h
index 3562724f7..763cac00f 100644
--- a/variants/lora_relay_v1/variant.h
+++ b/variants/lora_relay_v1/variant.h
@@ -117,8 +117,8 @@ static const uint8_t SCK = PIN_SPI_SCK;
 #define I2C_ADDR_BQ27441 0x55 // Battery gauge
 
 // CUSTOM GPIOs the SX1262
-// #define SX1262_CS (32)
-#define USE_SIM_RADIO
+#define SX1262_CS (32)
+
 #define USE_SEGGER
 #define SX1262_DIO1 (29)
 #define SX1262_DIO2 (30)
@@ -136,6 +136,10 @@ static const uint8_t SCK = PIN_SPI_SCK;
 #define ST7735_BACKLIGHT_EN (13)
 #define ST7735_RS (9)
 
+#define LORA_DISABLE_SENDING // The 1.1 version of this board browns out if the SX1262 transmits while the screen is on.  So you
+                             // can
+// have either a working SX1262 or a working screen
+
 #ifdef __cplusplus
 }
 #endif