commit 22be62dc55e8d3e216aa1ea09738f0e27a88d4fb
Author: Thomas Schöpping <tschoepp@cit-ec.uni-bielefeld.de>
Date:   Thu Sep 13 15:45:01 2018 +0200

    Reintroduced ChibiOS patch for non-DMA I2C access.
    Old patch could not be applied to latest version of ChibiOS anymore.

diff --git a/kernel/patches/I2C-without-DMA.patch b/kernel/patches/I2C-without-DMA.patch
new file mode 100644
index 0000000..dfa6be7
--- /dev/null
+++ b/kernel/patches/I2C-without-DMA.patch
@@ -0,0 +1,853 @@
+diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+index 6ade226..96c9da0 100644
+--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
++++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
+@@ -34,6 +34,7 @@
+ /* Driver local definitions.                                                 */
+ /*===========================================================================*/
+ 
++#if STM32_I2C_I2C1_USE_DMA
+ #define I2C1_RX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
+                        STM32_I2C1_RX_DMA_CHN)
+@@ -41,7 +42,9 @@
+ #define I2C1_TX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_TX_DMA_STREAM,                        \
+                        STM32_I2C1_TX_DMA_CHN)
++#endif
+ 
++#if STM32_I2C_I2C2_USE_DMA
+ #define I2C2_RX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_RX_DMA_STREAM,                        \
+                        STM32_I2C2_RX_DMA_CHN)
+@@ -49,7 +52,9 @@
+ #define I2C2_TX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C2_TX_DMA_STREAM,                        \
+                        STM32_I2C2_TX_DMA_CHN)
++#endif
+ 
++#if STM32_I2C_I2C3_USE_DMA
+ #define I2C3_RX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_RX_DMA_STREAM,                        \
+                        STM32_I2C3_RX_DMA_CHN)
+@@ -57,6 +62,7 @@
+ #define I2C3_TX_DMA_CHANNEL                                                 \
+   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
+                        STM32_I2C3_TX_DMA_CHN)
++#endif
+ 
+ /*===========================================================================*/
+ /* Driver constants.                                                         */
+@@ -72,6 +78,20 @@
+ #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
+   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
+ 
++#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
++
++#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
++  ((uint32_t)(I2C_SR1_RXNE))
++
++#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
++              I2C_SR1_BTF | I2C_SR1_RXNE))
++
++#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
++  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
++              I2C_SR1_TXE))
++
+ #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
+   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
+               I2C_SR1_BTF | I2C_SR1_TXE))
+@@ -129,8 +149,24 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
+   dp->SR1 = 0;
+ 
+   /* Stops the associated DMA streams.*/
+-  dmaStreamDisable(i2cp->dmatx);
+-  dmaStreamDisable(i2cp->dmarx);
++#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
++  if (&I2CD1 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
++#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
++  if (&I2CD2 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
++#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
++  if (&I2CD3 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
+ }
+ 
+ /**
+@@ -236,13 +272,17 @@ static void i2c_lld_set_opmode(I2CDriver *i2cp) {
+ }
+ 
+ /**
+- * @brief   I2C shared ISR code.
++ * @brief   I2C shared ISR code for DMA access.
+  *
+  * @param[in] i2cp      pointer to the @p I2CDriver object
+  *
+  * @notapi
+  */
+-static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
++#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                       \
++    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                       \
++    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                       \
++    defined(__DOXYGEN__)
++static void i2c_lld_serve_event_interrupt_dma(I2CDriver *i2cp) {
+   I2C_TypeDef *dp = i2cp->i2c;
+   uint32_t regSR2 = dp->SR2;
+   uint32_t event = dp->SR1;
+@@ -252,7 +292,7 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+      done by the DMA.*/
+   switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
+   case I2C_EV5_MASTER_MODE_SELECT:
+-    if ((i2cp->addr >> 8) > 0) { 
++    if ((i2cp->addr >> 8) > 0) {
+       /* 10-bit address: 1 1 1 1 0 X X R/W */
+       dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
+     } else {
+@@ -293,6 +333,140 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+   if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
+     (void)dp->SR2;
+ }
++#endif /* any I2CDx uses DMA mode */
++
++/**
++ * @brief   I2C shared ISR code for non-DMA access.
++ *
++ * @param[in] i2cp      pointer to the @p I2CDriver object
++ *
++ * @notapi
++ */
++#if (STM32_I2C_USE_I2C1 && !STM32_I2C_I2C1_USE_DMA) ||                      \
++    (STM32_I2C_USE_I2C2 && !STM32_I2C_I2C2_USE_DMA) ||                      \
++    (STM32_I2C_USE_I2C3 && !STM32_I2C_I2C3_USE_DMA) ||                      \
++    defined(__DOXYGEN__)
++static void i2c_lld_serve_event_interrupt_isr(I2CDriver *i2cp) {
++  I2C_TypeDef *dp = i2cp->i2c;
++  uint32_t regSR2 = dp->SR2;
++  uint32_t event = dp->SR1;
++
++  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
++  case I2C_EV5_MASTER_MODE_SELECT:
++    dp->CR2 |= I2C_CR2_ITBUFEN;
++    dp->DR = i2cp->addr;
++    break;
++  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
++    (void)dp->SR2; // clear ADDR flag
++    /* EV8_1 */
++    dp->DR = *(i2cp->txbuf);
++
++    ++i2cp->txbuf;
++    --i2cp->txbytes;
++
++    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
++     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
++    if (i2cp->txbytes == 0) {
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV6_MASTER_REC_MODE_SELECTED:
++    switch (i2cp->rxbytes) {
++    case 1:
++      dp->CR1 &= ~I2C_CR1_ACK;
++      (void)dp->SR2; // clear ADDR flag
++      dp->CR1 |= I2C_CR1_STOP;
++      break;
++    case 2:
++      (void)dp->SR2; // clear ADDR flag
++      /* EV6_1 */
++      dp->CR1 |= I2C_CR1_POS;
++      dp->CR1 &= ~I2C_CR1_ACK;
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++      break;
++    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
++      (void)dp->SR2; // clear ADDR flag
++      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
++       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++      break;
++    default: /* N > 2 */
++      (void)dp->SR2; // clear ADDR flag
++      break;
++    }
++    break;
++  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
++    if (i2cp->rxbytes > 3) {
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      --i2cp->rxbytes;
++    }
++    if (i2cp->rxbytes == 3) {
++      /* Disable this event for DataN-2, but force into event
++       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
++    osalDbgAssert(i2cp->rxbytes == 1, "more than 1 byte to be received");
++    *(i2cp->rxbuf) = dp->DR;
++    --i2cp->rxbytes;
++    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++    _i2c_wakeup_isr(i2cp);
++    break;
++  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
++    if (i2cp->rxbytes == 3) {
++      /* EV7_2 (N > 2) */
++      dp->CR1 &= ~I2C_CR1_ACK;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      dp->CR1 |= I2C_CR1_STOP;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      i2cp->rxbytes -= 2;
++      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
++      dp->CR2 |= I2C_CR2_ITBUFEN;
++    } else {
++      /* EV7_3 (N == 2) */
++      dp->CR1 |= I2C_CR1_STOP;
++      *(i2cp->rxbuf) = dp->DR;
++      ++i2cp->rxbuf;
++      *(i2cp->rxbuf) = dp->DR;
++      i2cp->rxbytes -= 2;
++
++      dp->CR1 &= ~I2C_CR1_POS;
++      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++
++      _i2c_wakeup_isr(i2cp);
++    }
++    break;
++  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
++    dp->DR = *(i2cp->txbuf);
++    ++i2cp->txbuf;
++    --i2cp->txbytes;
++
++    /* if this was the last byte, ensure that this event is not entered again */
++    if (i2cp->txbytes == 0) {
++      dp->CR2 &= ~I2C_CR2_ITBUFEN;
++    }
++    break;
++  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
++    if (i2cp->rxbytes > 0) {
++      /* start "read after write" operation (LSB of address = 1 => read) */
++      i2cp->addr |= 0x01;
++      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
++    } else {
++      dp->CR1 |= I2C_CR1_STOP;
++      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
++      _i2c_wakeup_isr(i2cp);
++    }
++    break;
++  default:
++    osalDbgAssert(i2cp->rxbytes != 1, "more than 1 byte to be received");
++    break;
++  }
++}
++#endif /* any I2CDx uses non-DMA mode */
+ 
+ /**
+  * @brief   DMA RX end IRQ handler.
+@@ -302,6 +476,10 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
+  *
+  * @notapi
+  */
++#if (STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                      \
++    (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                      \
++    (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA) ||                      \
++    defined(__DOXYGEN__)
+ static void i2c_lld_serve_rx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+   I2C_TypeDef *dp = i2cp->i2c;
+ 
+@@ -347,6 +525,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+      of R/W transaction itself.*/
+   dp->CR2 |= I2C_CR2_ITEVTEN;
+ }
++#endif /* any I2CDx uses DMA mode */
+ 
+ /**
+  * @brief   I2C error handler.
+@@ -359,8 +538,24 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
+ static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
+ 
+   /* Clears interrupt flags just to be safe.*/
+-  dmaStreamDisable(i2cp->dmatx);
+-  dmaStreamDisable(i2cp->dmarx);
++#if STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA
++  if (&I2CD1 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
++#if STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA
++  if (&I2CD2 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
++#if STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA
++  if (&I2CD3 == i2cp) {
++    dmaStreamDisable(i2cp->dmatx);
++    dmaStreamDisable(i2cp->dmarx);
++  }
++#endif
+ 
+   i2cp->errors = I2C_NO_ERROR;
+ 
+@@ -407,7 +602,11 @@ OSAL_IRQ_HANDLER(STM32_I2C1_EVENT_HANDLER) {
+ 
+   OSAL_IRQ_PROLOGUE();
+ 
+-  i2c_lld_serve_event_interrupt(&I2CD1);
++#if STM32_I2C_I2C1_USE_DMA
++  i2c_lld_serve_event_interrupt_dma(&I2CD1);
++#else
++  i2c_lld_serve_event_interrupt_isr(&I2CD1);
++#endif
+ 
+   OSAL_IRQ_EPILOGUE();
+ }
+@@ -437,7 +636,11 @@ OSAL_IRQ_HANDLER(STM32_I2C2_EVENT_HANDLER) {
+ 
+   OSAL_IRQ_PROLOGUE();
+ 
+-  i2c_lld_serve_event_interrupt(&I2CD2);
++#if STM32_I2C_I2C2_USE_DMA
++  i2c_lld_serve_event_interrupt_dma(&I2CD2);
++#else
++  i2c_lld_serve_event_interrupt_isr(&I2CD2);
++#endif
+ 
+   OSAL_IRQ_EPILOGUE();
+ }
+@@ -469,7 +672,11 @@ OSAL_IRQ_HANDLER(STM32_I2C3_EVENT_HANDLER) {
+ 
+   OSAL_IRQ_PROLOGUE();
+ 
+-  i2c_lld_serve_event_interrupt(&I2CD3);
++#if STM32_I2C_I2C3_USE_DMA
++  i2c_lld_serve_event_interrupt_dma(&I2CD3);
++#else
++  i2c_lld_serve_event_interrupt_isr(&I2CD3);
++#endif
+ 
+   OSAL_IRQ_EPILOGUE();
+ }
+@@ -506,24 +713,30 @@ void i2c_lld_init(void) {
+   i2cObjectInit(&I2CD1);
+   I2CD1.thread = NULL;
+   I2CD1.i2c    = I2C1;
++#if STM32_I2C_I2C1_USE_DMA
+   I2CD1.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
+   I2CD1.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
++#endif
+ #endif /* STM32_I2C_USE_I2C1 */
+ 
+ #if STM32_I2C_USE_I2C2
+   i2cObjectInit(&I2CD2);
+   I2CD2.thread = NULL;
+   I2CD2.i2c    = I2C2;
++#if STM32_I2C_I2C2_USE_DMA
+   I2CD2.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
+   I2CD2.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
++#endif
+ #endif /* STM32_I2C_USE_I2C2 */
+ 
+ #if STM32_I2C_USE_I2C3
+   i2cObjectInit(&I2CD3);
+   I2CD3.thread = NULL;
+   I2CD3.i2c    = I2C3;
++#if STM32_I2C_I2C3_USE_DMA
+   I2CD3.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
+   I2CD3.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
++#endif
+ #endif /* STM32_I2C_USE_I2C3 */
+ }
+ 
+@@ -540,20 +753,24 @@ void i2c_lld_start(I2CDriver *i2cp) {
+   /* If in stopped state then enables the I2C and DMA clocks.*/
+   if (i2cp->state == I2C_STOP) {
+ 
+-    i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+-                      STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
+-                      STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
+-                      STM32_DMA_CR_DIR_M2P;
+-    i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
+-                      STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
+-                      STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
+-                      STM32_DMA_CR_DIR_P2M;
+-
+ #if STM32_I2C_USE_I2C1
+     if (&I2CD1 == i2cp) {
++#if STM32_I2C_I2C1_USE_DMA
+       bool b;
+ 
++      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_M2P;
++      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_P2M;
++#endif
++
+       rccResetI2C1();
++
++#if STM32_I2C_I2C1_USE_DMA
+       b = dmaStreamAllocate(i2cp->dmarx,
+                             STM32_I2C_I2C1_IRQ_PRIORITY,
+                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+@@ -564,22 +781,52 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif
++
+       rccEnableI2C1(true);
+       nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+       nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
+ 
++#if STM32_I2C_I2C1_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
++
++      /* I2C registers pointed by the DMA.*/
++      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
++      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
++#endif
++
++      /* Reset i2c peripheral.*/
++      dp->CR1 = I2C_CR1_SWRST;
++      dp->CR1 = 0;
++#if STM32_I2C_I2C1_USE_DMA
++      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
++#else
++      dp->CR2 = I2C_CR2_ITERREN;
++#endif
+     }
+ #endif /* STM32_I2C_USE_I2C1 */
+ 
+ #if STM32_I2C_USE_I2C2
+     if (&I2CD2 == i2cp) {
++#if STM32_I2C_I2C2_USE_DMA
+       bool b;
+ 
++      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_M2P;
++      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_P2M;
++#endif
++
+       rccResetI2C2();
++
++#if STM32_I2C_I2C2_USE_DMA
+       b = dmaStreamAllocate(i2cp->dmarx,
+                             STM32_I2C_I2C2_IRQ_PRIORITY,
+                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+@@ -590,22 +837,52 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif
++
+       rccEnableI2C2(true);
+       nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+       nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
+ 
++#if STM32_I2C_I2C2_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
++
++      /* I2C registers pointed by the DMA.*/
++      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
++      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
++#endif
++
++      /* Reset i2c peripheral.*/
++      dp->CR1 = I2C_CR1_SWRST;
++      dp->CR1 = 0;
++#if STM32_I2C_I2C2_USE_DMA
++      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
++#else
++      dp->CR2 = I2C_CR2_ITERREN;
++#endif
+     }
+ #endif /* STM32_I2C_USE_I2C2 */
+ 
+ #if STM32_I2C_USE_I2C3
+     if (&I2CD3 == i2cp) {
++#if STM32_I2C_I2C3_USE_DMA
+       bool b;
+ 
++      i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_M2P;
++      i2cp->rxdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
++                        STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
++                        STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
++                        STM32_DMA_CR_DIR_P2M;
++#endif
++
+       rccResetI2C3();
++
++#if STM32_I2C_I2C3_USE_DMA
+       b = dmaStreamAllocate(i2cp->dmarx,
+                             STM32_I2C_I2C3_IRQ_PRIORITY,
+                             (stm32_dmaisr_t)i2c_lld_serve_rx_end_irq,
+@@ -616,27 +893,35 @@ void i2c_lld_start(I2CDriver *i2cp) {
+                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
+                             (void *)i2cp);
+       osalDbgAssert(!b, "stream already allocated");
++#endif
++
+       rccEnableI2C3(true);
+       nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+       nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
+ 
++#if STM32_I2C_I2C3_USE_DMA
+       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
+       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
+                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
++
++      /* I2C registers pointed by the DMA.*/
++      dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
++      dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
++#endif
++
++      /* Reset i2c peripheral.*/
++      dp->CR1 = I2C_CR1_SWRST;
++      dp->CR1 = 0;
++#if STM32_I2C_I2C3_USE_DMA
++      dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
++#else
++      dp->CR2 = I2C_CR2_ITERREN;
++#endif
+     }
+ #endif /* STM32_I2C_USE_I2C3 */
+   }
+ 
+-  /* I2C registers pointed by the DMA.*/
+-  dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
+-  dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
+-
+-  /* Reset i2c peripheral.*/
+-  dp->CR1 = I2C_CR1_SWRST;
+-  dp->CR1 = 0;
+-  dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
+-
+   /* Setup I2C parameters.*/
+   i2c_lld_set_clock(i2cp);
+   i2c_lld_set_opmode(i2cp);
+@@ -659,11 +944,13 @@ void i2c_lld_stop(I2CDriver *i2cp) {
+ 
+     /* I2C disable.*/
+     i2c_lld_abort_operation(i2cp);
+-    dmaStreamRelease(i2cp->dmatx);
+-    dmaStreamRelease(i2cp->dmarx);
+ 
+ #if STM32_I2C_USE_I2C1
+     if (&I2CD1 == i2cp) {
++#if STM32_I2C_I2C1_USE_DMA
++      dmaStreamRelease(i2cp->dmatx);
++      dmaStreamRelease(i2cp->dmarx);
++ #endif
+       nvicDisableVector(I2C1_EV_IRQn);
+       nvicDisableVector(I2C1_ER_IRQn);
+       rccDisableI2C1();
+@@ -672,6 +959,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
+ 
+ #if STM32_I2C_USE_I2C2
+     if (&I2CD2 == i2cp) {
++#if STM32_I2C_I2C2_USE_DMA
++      dmaStreamRelease(i2cp->dmatx);
++      dmaStreamRelease(i2cp->dmarx);
++ #endif
+       nvicDisableVector(I2C2_EV_IRQn);
+       nvicDisableVector(I2C2_ER_IRQn);
+       rccDisableI2C2();
+@@ -680,6 +971,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
+ 
+ #if STM32_I2C_USE_I2C3
+     if (&I2CD3 == i2cp) {
++#if STM32_I2C_I2C3_USE_DMA
++      dmaStreamRelease(i2cp->dmatx);
++      dmaStreamRelease(i2cp->dmarx);
++ #endif
+       nvicDisableVector(I2C3_EV_IRQn);
+       nvicDisableVector(I2C3_ER_IRQn);
+       rccDisableI2C3();
+@@ -730,10 +1025,43 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
+   /* Releases the lock from high level driver.*/
+   osalSysUnlock();
+ 
+-  /* RX DMA setup.*/
+-  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+-  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+-  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++  /* RX (DMA) setup.*/
++#if STM32_I2C_USE_I2C1
++  if (&I2CD1 == i2cp) {
++#if STM32_I2C_I2C1_USE_DMA
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
++#if STM32_I2C_USE_I2C2
++  if (&I2CD2 == i2cp) {
++#if STM32_I2C_I2C2_USE_DMA
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
++#if STM32_I2C_USE_I2C3
++  if (&I2CD3 == i2cp) {
++#if STM32_I2C_I2C3_USE_DMA
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
+ 
+   /* Calculating the time window for the timeout on the busy bus condition.*/
+   start = osalOsGetSystemTimeX();
+@@ -810,15 +1138,61 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
+   /* Releases the lock from high level driver.*/
+   osalSysUnlock();
+ 
+-  /* TX DMA setup.*/
+-  dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
+-  dmaStreamSetMemory0(i2cp->dmatx, txbuf);
+-  dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
+-
+-  /* RX DMA setup.*/
+-  dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
+-  dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
+-  dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++  /* TX (DMA) and RX (DMA) setup */
++#if STM32_I2C_USE_I2C1
++  if (&I2CD1 == i2cp) {
++#if STM32_I2C_I2C1_USE_DMA
++    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
++    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
++    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
++
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->txbuf = txbuf;
++    i2cp->txbytes = txbytes;
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
++#if STM32_I2C_USE_I2C2
++  if (&I2CD2 == i2cp) {
++#if STM32_I2C_I2C2_USE_DMA
++    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
++    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
++    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
++
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->txbuf = txbuf;
++    i2cp->txbytes = txbytes;
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
++#if STM32_I2C_USE_I2C3
++  if (&I2CD3 == i2cp) {
++#if STM32_I2C_I2C3_USE_DMA
++    dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
++    dmaStreamSetMemory0(i2cp->dmatx, txbuf);
++    dmaStreamSetTransactionSize(i2cp->dmatx, txbytes);
++
++    dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
++    dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
++    dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
++#else
++    i2cp->txbuf = txbuf;
++    i2cp->txbytes = txbytes;
++    i2cp->rxbuf = rxbuf;
++    i2cp->rxbytes = rxbytes;
++#endif
++  }
++#endif
+ 
+   /* Calculating the time window for the timeout on the busy bus condition.*/
+   start = osalOsGetSystemTimeX();
+diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
+index 1328d47..68f91e1 100644
+--- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
++++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
+@@ -104,6 +104,33 @@
+ #endif
+ 
+ /**
++ * @brief   I2C1 DMA enable switch.
++ * @details If set to @p TRUE the I2C1 driver will use DMA.
++ * @note    The default is @p TRUE.
++ */
++#if !defined(STM32_I2C_I2C1_USE_DMA) || defined(__DOXYGEN__)
++#define STM32_I2C_I2C1_USE_DMA              TRUE
++#endif
++
++/**
++ * @brief   I2C2 DMA enable switch.
++ * @details If set to @p TRUE the I2C2 driver will use DMA.
++ * @note    The default is @p TRUE.
++ */
++#if !defined(STM32_I2C_I2C2_USE_DMA) || defined(__DOXYGEN__)
++#define STM32_I2C_I2C2_USE_DMA              TRUE
++#endif
++
++/**
++ * @brief   I2C3 DMA enable switch.
++ * @details If set to @p TRUE the I2C3 driver will use DMA.
++ * @note    The default is @p TRUE.
++ */
++#if !defined(STM32_I2C_I2C3_USE_DMA) || defined(__DOXYGEN__)
++#define STM32_I2C_I2C3_USE_DMA              TRUE
++#endif
++
++/**
+ * @brief   I2C1 DMA priority (0..3|lowest..highest).
+ * @note    The priority level is used for both the TX and RX DMA streams but
+ *          because of the streams ordering the RX stream has always priority
+@@ -250,16 +277,19 @@
+ #endif
+ 
+ #if STM32_I2C_USE_I2C1 &&                                                   \
++    STM32_I2C_I2C1_USE_DMA &&                                               \
+     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
+ #error "Invalid DMA priority assigned to I2C1"
+ #endif
+ 
+ #if STM32_I2C_USE_I2C2 &&                                                   \
++    STM32_I2C_I2C2_USE_DMA &&                                               \
+     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C2_DMA_PRIORITY)
+ #error "Invalid DMA priority assigned to I2C2"
+ #endif
+ 
+ #if STM32_I2C_USE_I2C3 &&                                                   \
++    STM32_I2C_I2C3_USE_DMA &&                                               \
+     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C3_DMA_PRIORITY)
+ #error "Invalid DMA priority assigned to I2C3"
+ #endif
+@@ -316,7 +346,10 @@
+ #endif
+ #endif /* STM32_ADVANCED_DMA */
+ 
+-#if !defined(STM32_DMA_REQUIRED)
++#if ((STM32_I2C_USE_I2C1 && STM32_I2C_I2C1_USE_DMA) ||                       \
++     (STM32_I2C_USE_I2C2 && STM32_I2C_I2C2_USE_DMA) ||                       \
++     (STM32_I2C_USE_I2C3 && STM32_I2C_I2C3_USE_DMA)) &&                      \
++    !defined(STM32_DMA_REQUIRED)
+ #define STM32_DMA_REQUIRED
+ #endif
+ 
+@@ -437,21 +470,52 @@ struct I2CDriver {
+    */
+   i2caddr_t                 addr;
+   /**
+-   * @brief RX DMA mode bit mask.
+-   */
+-  uint32_t                  rxdmamode;
+-  /**
+-   * @brief TX DMA mode bit mask.
+-   */
+-  uint32_t                  txdmamode;
+-  /**
+-   * @brief     Receive DMA channel.
+-   */
+-  const stm32_dma_stream_t  *dmarx;
+-  /**
+-   * @brief     Transmit DMA channel.
++   * @brief   Anonymous union to store transmission related data for either DMA or non-DMA mode.
+    */
+-  const stm32_dma_stream_t  *dmatx;
++  union {
++    /**
++     * @brief   Anonymous struct to store data for DMA mode.
++     */
++    struct {
++      /**
++       * @brief RX DMA mode bit mask.
++       */
++      uint32_t                  rxdmamode;
++      /**
++       * @brief TX DMA mode bit mask.
++       */
++      uint32_t                  txdmamode;
++      /**
++       * @brief     Receive DMA channel.
++       */
++      const stm32_dma_stream_t  *dmarx;
++      /**
++       * @brief     Transmit DMA channel.
++       */
++      const stm32_dma_stream_t  *dmatx;
++    };
++    /**
++     * @brief   Anonymous struct to store data for non-DMA mode.
++     */
++    struct {
++      /**
++       * @brief   Receive buffer.
++       */
++      uint8_t                   *rxbuf;
++      /**
++       * @brief   Size of the receive buffer.
++       */
++      size_t                    rxbytes;
++      /**
++       * @brief   Transmit buffer.
++       */
++      const uint8_t             *txbuf;
++      /**
++       * @brief   Size of the transmit buffer.
++       */
++      size_t                    txbytes;
++    };
++  };
+   /**
+    * @brief     Pointer to the I2Cx registers block.
+    */
diff --git a/kernel/patches/Introduced-I2C-without-DMA.patch b/kernel/patches/Introduced-I2C-without-DMA.patch
deleted file mode 100644
index d50e930..0000000
--- a/kernel/patches/Introduced-I2C-without-DMA.patch
+++ /dev/null
@@ -1,479 +0,0 @@
-From 736d3be25b7389b6130e0c372328aa56e2532250 Mon Sep 17 00:00:00 2001
-From: =?UTF-8?q?Thomas=20Sch=C3=B6pping?= <tschoepp@cit-ec.uni-bielefeld.de>
-Date: Mon, 12 Jun 2017 17:28:49 +0200
-Subject: [PATCH] Introduced I2C without DMA (I2Cv1 only).
-
----
- os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c | 181 ++++++++++++++++++++++++++++-
- os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h |  30 +++++
- 2 files changed, 210 insertions(+), 1 deletion(-)
-
-diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
-index 20b8cf8..b2cfb59 100644
---- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
-+++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.c
-@@ -34,6 +34,7 @@
- /* Driver local definitions.                                                 */
- /*===========================================================================*/
- 
-+#if STM32_I2C_USE_DMA
- #define I2C1_RX_DMA_CHANNEL                                                 \
-   STM32_DMA_GETCHANNEL(STM32_I2C_I2C1_RX_DMA_STREAM,                        \
-                        STM32_I2C1_RX_DMA_CHN)
-@@ -57,6 +58,7 @@
- #define I2C3_TX_DMA_CHANNEL                                                 \
-   STM32_DMA_GETCHANNEL(STM32_I2C_I2C3_TX_DMA_STREAM,                        \
-                        STM32_I2C3_TX_DMA_CHN)
-+#endif /* STM32_I2C_USE_DMA */
- 
- /*===========================================================================*/
- /* Driver constants.                                                         */
-@@ -72,6 +74,20 @@
- #define I2C_EV6_MASTER_REC_MODE_SELECTED                                    \
-   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_ADDR))
- 
-+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED                                    \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) | I2C_SR1_RXNE))
-+
-+#define I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP                               \
-+  ((uint32_t)(                                      I2C_SR1_RXNE))
-+
-+#define I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED                              \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY)<< 16) |                         \
-+              I2C_SR1_BTF | I2C_SR1_RXNE))
-+
-+#define I2C_EV8_MASTER_BYTE_TRANSMITTING                                    \
-+  ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA)<< 16) |           \
-+              I2C_SR1_TXE))
-+
- #define I2C_EV8_2_MASTER_BYTE_TRANSMITTED                                   \
-   ((uint32_t)(((I2C_SR2_MSL | I2C_SR2_BUSY | I2C_SR2_TRA) << 16) |          \
-               I2C_SR1_BTF | I2C_SR1_TXE))
-@@ -128,9 +144,11 @@ static void i2c_lld_abort_operation(I2CDriver *i2cp) {
-   dp->CR2 = 0;
-   dp->SR1 = 0;
- 
-+#if STM32_I2C_USE_DMA
-   /* Stops the associated DMA streams.*/
-   dmaStreamDisable(i2cp->dmatx);
-   dmaStreamDisable(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- }
- 
- /**
-@@ -247,12 +265,13 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
-   uint32_t regSR2 = dp->SR2;
-   uint32_t event = dp->SR1;
- 
-+#if STM32_I2C_USE_DMA
-   /* Interrupts are disabled just before dmaStreamEnable() because there
-      is no need of interrupts until next transaction begin. All the work is
-      done by the DMA.*/
-   switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
-   case I2C_EV5_MASTER_MODE_SELECT:
--    if ((i2cp->addr >> 8) > 0) { 
-+    if ((i2cp->addr >> 8) > 0) {
-       /* 10-bit address: 1 1 1 1 0 X X R/W */
-       dp->DR = 0xF0 | (0x6 & (i2cp->addr >> 8)) | (0x1 & i2cp->addr);
-     } else {
-@@ -292,8 +311,125 @@ static void i2c_lld_serve_event_interrupt(I2CDriver *i2cp) {
-   /* Clear ADDR flag. */
-   if (event & (I2C_SR1_ADDR | I2C_SR1_ADD10))
-     (void)dp->SR2;
-+#else
-+  switch (I2C_EV_MASK & (event | (regSR2 << 16))) {
-+  case I2C_EV5_MASTER_MODE_SELECT:
-+    dp->CR2 |= I2C_CR2_ITBUFEN;
-+    dp->DR = i2cp->addr;
-+    break;
-+  case I2C_EV6_MASTER_TRA_MODE_SELECTED:
-+    (void)dp->SR2; // clear ADDR flag
-+    /* EV8_1 */
-+    dp->DR = *(i2cp->txbuf);
-+
-+    ++i2cp->txbuf;
-+    --i2cp->txbytes;
-+
-+    /* if N == 1, skip the I2C_EV8_MASTER_BYTE_TRANSMITTING event
-+     * but enter I2C_EV8_2_MASTER_BYTE_TRANSMITTED next */
-+    if (i2cp->txbytes == 0) {
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV6_MASTER_REC_MODE_SELECTED:
-+    switch (i2cp->rxbytes) {
-+    case 1:
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      (void)dp->SR2; // clear ADDR flag
-+      dp->CR1 |= I2C_CR1_STOP;
-+      break;
-+    case 2:
-+      (void)dp->SR2; // clear ADDR flag
-+      /* EV6_1 */
-+      dp->CR1 |= I2C_CR1_POS;
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+      break;
-+    case 3: /* N == 3 is a very special case, since EV7 is completely skipped */
-+      (void)dp->SR2; // clear ADDR flag
-+      /* Disable the I2C_EV7_MASTER_REC_BYTE_RECEIVED event
-+       * but enter I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP next */
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+      break;
-+    default: /* N > 2 */
-+      (void)dp->SR2; // clear ADDR flag
-+      break;
-+    }
-+    break;
-+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED:
-+    if (i2cp->rxbytes > 3) {
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      --i2cp->rxbytes;
-+    }
-+    if (i2cp->rxbytes == 3) {
-+      /* Disable this event for DataN-2, but force into event
-+       * I2C_EV7_2_EV7_3_MASTER_REC_BYTE_RECEIVED_QUEUED by not reading dp->DR. */
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP:
-+    osalDbgAssert(i2cp->rxbytes == 1, "more than 1 byte to be received");
-+    *(i2cp->rxbuf) = dp->DR;
-+    --i2cp->rxbytes;
-+    dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+    _i2c_wakeup_isr(i2cp);
-+    break;
-+  case I2C_EV7_2_EV7_3_MASTER_REC_BYTE_QUEUED:
-+    if (i2cp->rxbytes == 3) {
-+      /* EV7_2 (N > 2) */
-+      dp->CR1 &= ~I2C_CR1_ACK;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      dp->CR1 |= I2C_CR1_STOP;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      i2cp->rxbytes -= 2;
-+      /* enable I2C_EV7_MASTER_REC_BYTE_RECEIVED_STOP event */
-+      dp->CR2 |= I2C_CR2_ITBUFEN;
-+    } else {
-+      /* EV7_3 (N == 2) */
-+      dp->CR1 |= I2C_CR1_STOP;
-+      *(i2cp->rxbuf) = dp->DR;
-+      ++i2cp->rxbuf;
-+      *(i2cp->rxbuf) = dp->DR;
-+      i2cp->rxbytes -= 2;
-+
-+      dp->CR1 &= ~I2C_CR1_POS;
-+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+
-+      _i2c_wakeup_isr(i2cp);
-+    }
-+    break;
-+  case I2C_EV8_MASTER_BYTE_TRANSMITTING:
-+    dp->DR = *(i2cp->txbuf);
-+    ++i2cp->txbuf;
-+    --i2cp->txbytes;
-+
-+    /* if this was the last byte, ensure that this event is not entered again */
-+    if (i2cp->txbytes == 0) {
-+      dp->CR2 &= ~I2C_CR2_ITBUFEN;
-+    }
-+    break;
-+  case I2C_EV8_2_MASTER_BYTE_TRANSMITTED:
-+    if (i2cp->rxbytes > 0) {
-+      /* start "read after write" operation (LSB of address = 1 => read) */
-+      i2cp->addr |= 0x01;
-+      dp->CR1 |= I2C_CR1_START | I2C_CR1_ACK;
-+    } else {
-+      dp->CR1 |= I2C_CR1_STOP;
-+      dp->CR2 &= ~(I2C_CR2_ITEVTEN | I2C_CR2_ITBUFEN);
-+      _i2c_wakeup_isr(i2cp);
-+    }
-+    break;
-+  default:
-+    osalDbgAssert(i2cp->rxbytes != 1, "more than 1 byte to be received");
-+    break;
-+  }
-+#endif /* STM32_I2C_USE_DMA */
- }
- 
-+#if STM32_I2C_USE_DMA
- /**
-  * @brief   DMA RX end IRQ handler.
-  *
-@@ -347,6 +483,7 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
-      of R/W transaction itself.*/
-   dp->CR2 |= I2C_CR2_ITEVTEN;
- }
-+#endif /* STM32_I2C_USE_DMA */
- 
- /**
-  * @brief   I2C error handler.
-@@ -358,9 +495,11 @@ static void i2c_lld_serve_tx_end_irq(I2CDriver *i2cp, uint32_t flags) {
-  */
- static void i2c_lld_serve_error_interrupt(I2CDriver *i2cp, uint16_t sr) {
- 
-+#if STM32_I2C_USE_DMA
-   /* Clears interrupt flags just to be safe.*/
-   dmaStreamDisable(i2cp->dmatx);
-   dmaStreamDisable(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- 
-   i2cp->errors = I2C_NO_ERROR;
- 
-@@ -506,24 +645,30 @@ void i2c_lld_init(void) {
-   i2cObjectInit(&I2CD1);
-   I2CD1.thread = NULL;
-   I2CD1.i2c    = I2C1;
-+#if STM32_I2C_USE_DMA
-   I2CD1.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C1_RX_DMA_STREAM);
-   I2CD1.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C1_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C1 */
- 
- #if STM32_I2C_USE_I2C2
-   i2cObjectInit(&I2CD2);
-   I2CD2.thread = NULL;
-   I2CD2.i2c    = I2C2;
-+#if STM32_I2C_USE_DMA
-   I2CD2.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C2_RX_DMA_STREAM);
-   I2CD2.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C2_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C2 */
- 
- #if STM32_I2C_USE_I2C3
-   i2cObjectInit(&I2CD3);
-   I2CD3.thread = NULL;
-   I2CD3.i2c    = I2C3;
-+#if STM32_I2C_USE_DMA
-   I2CD3.dmarx  = STM32_DMA_STREAM(STM32_I2C_I2C3_RX_DMA_STREAM);
-   I2CD3.dmatx  = STM32_DMA_STREAM(STM32_I2C_I2C3_TX_DMA_STREAM);
-+#endif /* STM32_I2C_USE_DMA */
- #endif /* STM32_I2C_USE_I2C3 */
- }
- 
-@@ -540,6 +685,7 @@ void i2c_lld_start(I2CDriver *i2cp) {
-   /* If in stopped state then enables the I2C and DMA clocks.*/
-   if (i2cp->state == I2C_STOP) {
- 
-+#if STM32_I2C_USE_DMA
-     i2cp->txdmamode = STM32_DMA_CR_PSIZE_BYTE | STM32_DMA_CR_MSIZE_BYTE |
-                       STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
-                       STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
-@@ -548,9 +694,11 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                       STM32_DMA_CR_MINC       | STM32_DMA_CR_DMEIE |
-                       STM32_DMA_CR_TEIE       | STM32_DMA_CR_TCIE |
-                       STM32_DMA_CR_DIR_P2M;
-+#endif /* STM32_I2C_USE_DMA */
- 
- #if STM32_I2C_USE_I2C1
-     if (&I2CD1 == i2cp) {
-+#if STM32_I2C_USE_DMA
-       bool b;
- 
-       rccResetI2C1();
-@@ -564,19 +712,23 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       osalDbgAssert(!b, "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C1(FALSE);
-       nvicEnableVector(I2C1_EV_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
-       nvicEnableVector(I2C1_ER_IRQn, STM32_I2C_I2C1_IRQ_PRIORITY);
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C1_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C1_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C1_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C1 */
- 
- #if STM32_I2C_USE_I2C2
-     if (&I2CD2 == i2cp) {
-+#if STM32_I2C_USE_DMA
-       bool b;
- 
-       rccResetI2C2();
-@@ -590,19 +742,23 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       osalDbgAssert(!b, "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C2(FALSE);
-       nvicEnableVector(I2C2_EV_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
-       nvicEnableVector(I2C2_ER_IRQn, STM32_I2C_I2C2_IRQ_PRIORITY);
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C2_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C2_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C2_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C2 */
- 
- #if STM32_I2C_USE_I2C3
-     if (&I2CD3 == i2cp) {
-+#if STM32_I2C_USE_DMA
-       bool b;
- 
-       rccResetI2C3();
-@@ -616,26 +772,35 @@ void i2c_lld_start(I2CDriver *i2cp) {
-                             (stm32_dmaisr_t)i2c_lld_serve_tx_end_irq,
-                             (void *)i2cp);
-       osalDbgAssert(!b, "stream already allocated");
-+#endif /* STM32_I2C_USE_DMA */
-       rccEnableI2C3(FALSE);
-       nvicEnableVector(I2C3_EV_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
-       nvicEnableVector(I2C3_ER_IRQn, STM32_I2C_I2C3_IRQ_PRIORITY);
- 
-+#if STM32_I2C_USE_DMA
-       i2cp->rxdmamode |= STM32_DMA_CR_CHSEL(I2C3_RX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
-       i2cp->txdmamode |= STM32_DMA_CR_CHSEL(I2C3_TX_DMA_CHANNEL) |
-                        STM32_DMA_CR_PL(STM32_I2C_I2C3_DMA_PRIORITY);
-+#endif /* STM32_I2C_USE_DMA */
-     }
- #endif /* STM32_I2C_USE_I2C3 */
-   }
- 
-+#if STM32_I2C_USE_DMA
-   /* I2C registers pointed by the DMA.*/
-   dmaStreamSetPeripheral(i2cp->dmarx, &dp->DR);
-   dmaStreamSetPeripheral(i2cp->dmatx, &dp->DR);
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Reset i2c peripheral.*/
-   dp->CR1 = I2C_CR1_SWRST;
-   dp->CR1 = 0;
-+#if STM32_I2C_USE_DMA
-   dp->CR2 = I2C_CR2_ITERREN | I2C_CR2_DMAEN;
-+#else
-+  dp->CR2 = I2C_CR2_ITERREN;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Setup I2C parameters.*/
-   i2c_lld_set_clock(i2cp);
-@@ -659,8 +824,10 @@ void i2c_lld_stop(I2CDriver *i2cp) {
- 
-     /* I2C disable.*/
-     i2c_lld_abort_operation(i2cp);
-+#if STM32_I2C_USE_DMA
-     dmaStreamRelease(i2cp->dmatx);
-     dmaStreamRelease(i2cp->dmarx);
-+#endif /* STM32_I2C_USE_DMA */
- 
- #if STM32_I2C_USE_I2C1
-     if (&I2CD1 == i2cp) {
-@@ -730,10 +897,15 @@ msg_t i2c_lld_master_receive_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   /* Releases the lock from high level driver.*/
-   osalSysUnlock();
- 
-+#if STM32_I2C_USE_DMA
-   /* RX DMA setup.*/
-   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
-   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
-   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
-+#else
-+  i2cp->rxbuf = rxbuf;
-+  i2cp->rxbytes = rxbytes;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Calculating the time window for the timeout on the busy bus condition.*/
-   start = osalOsGetSystemTimeX();
-@@ -810,6 +982,7 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   /* Releases the lock from high level driver.*/
-   osalSysUnlock();
- 
-+#if STM32_I2C_USE_DMA
-   /* TX DMA setup.*/
-   dmaStreamSetMode(i2cp->dmatx, i2cp->txdmamode);
-   dmaStreamSetMemory0(i2cp->dmatx, txbuf);
-@@ -819,6 +992,12 @@ msg_t i2c_lld_master_transmit_timeout(I2CDriver *i2cp, i2caddr_t addr,
-   dmaStreamSetMode(i2cp->dmarx, i2cp->rxdmamode);
-   dmaStreamSetMemory0(i2cp->dmarx, rxbuf);
-   dmaStreamSetTransactionSize(i2cp->dmarx, rxbytes);
-+#else
-+  i2cp->txbuf = txbuf;
-+  i2cp->txbytes = txbytes;
-+  i2cp->rxbuf = rxbuf;
-+  i2cp->rxbytes = rxbytes;
-+#endif /* STM32_I2C_USE_DMA */
- 
-   /* Calculating the time window for the timeout on the busy bus condition.*/
-   start = osalOsGetSystemTimeX();
-diff --git a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
-index a812ceb..127c708 100644
---- a/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
-+++ b/os/hal/ports/STM32/LLD/I2Cv1/hal_i2c_lld.h
-@@ -76,6 +76,15 @@
- #endif
- 
- /**
-+ * @brief   I2C data transfer use dma switch.
-+ * @details If set to @p TRUE the support for I2C DMA is included.
-+ * @note    The default is @p FALSE.
-+ */
-+#if !defined(STM32_I2C_USE_DMA) || defined(__DOXYGEN__)
-+#define STM32_I2C_USE_DMA                   TRUE
-+#endif
-+
-+/**
-  * @brief   I2C timeout on busy condition in milliseconds.
-  */
- #if !defined(STM32_I2C_BUSY_TIMEOUT) || defined(__DOXYGEN__)
-@@ -249,6 +258,7 @@
- #error "Invalid IRQ priority assigned to I2C3"
- #endif
- 
-+#if STM32_I2C_USE_DMA
- #if STM32_I2C_USE_I2C1 &&                                                   \
-     !STM32_DMA_IS_VALID_PRIORITY(STM32_I2C_I2C1_DMA_PRIORITY)
- #error "Invalid DMA priority assigned to I2C1"
-@@ -319,6 +329,7 @@
- #if !defined(STM32_DMA_REQUIRED)
- #define STM32_DMA_REQUIRED
- #endif
-+#endif /* STM32_I2C_USE_DMA */
- 
- /* Check clock range. */
- #if defined(STM32F4XX)
-@@ -436,6 +447,7 @@ struct I2CDriver {
-    * @brief     Current slave address without R/W bit.
-    */
-   i2caddr_t                 addr;
-+#if STM32_I2C_USE_DMA
-   /**
-    * @brief RX DMA mode bit mask.
-    */
-@@ -452,6 +464,24 @@ struct I2CDriver {
-    * @brief     Transmit DMA channel.
-    */
-   const stm32_dma_stream_t  *dmatx;
-+#else
-+  /**
-+   * @brief     Receive buffer.
-+   */
-+  uint8_t                   *rxbuf;
-+  /**
-+   * @brief     Receive buffer size.
-+   */
-+  size_t                    rxbytes;
-+  /**
-+   * @brief     Transmit buffer.
-+   */
-+  const uint8_t             *txbuf;
-+  /**
-+   * @brief     Transmit buffer size.
-+   */
-+  size_t                    txbytes;
-+#endif /* STM32_I2C_USE_DMA */
-   /**
-    * @brief     Pointer to the I2Cx registers block.
-    */
--- 
-2.7.4
-
diff --git a/modules/DiWheelDrive_1-1/mcuconf.h b/modules/DiWheelDrive_1-1/mcuconf.h
index 4ebd59e..d79b32c 100644
--- a/modules/DiWheelDrive_1-1/mcuconf.h
+++ b/modules/DiWheelDrive_1-1/mcuconf.h
@@ -110,6 +110,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define STM32_I2C_BUSY_TIMEOUT              50
 #define STM32_I2C_I2C1_IRQ_PRIORITY         5
 #define STM32_I2C_I2C2_IRQ_PRIORITY         5
+#define STM32_I2C_I2C1_USE_DMA              TRUE
+#define STM32_I2C_I2C2_USE_DMA              TRUE
 #define STM32_I2C_I2C1_DMA_PRIORITY         3
 #define STM32_I2C_I2C2_DMA_PRIORITY         3
 #define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure")
diff --git a/modules/LightRing_1-0/mcuconf.h b/modules/LightRing_1-0/mcuconf.h
index 68e1fd3..6983b1d 100644
--- a/modules/LightRing_1-0/mcuconf.h
+++ b/modules/LightRing_1-0/mcuconf.h
@@ -110,6 +110,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 #define STM32_I2C_BUSY_TIMEOUT              50
 #define STM32_I2C_I2C1_IRQ_PRIORITY         5
 #define STM32_I2C_I2C2_IRQ_PRIORITY         5
+#define STM32_I2C_I2C1_USE_DMA              TRUE
+#define STM32_I2C_I2C2_USE_DMA              FALSE
 #define STM32_I2C_I2C1_DMA_PRIORITY         3
 #define STM32_I2C_I2C2_DMA_PRIORITY         3
 #define STM32_I2C_DMA_ERROR_HOOK(i2cp)      osalSysHalt("DMA failure")
diff --git a/modules/LightRing_1-0/module.c b/modules/LightRing_1-0/module.c
index 16611b0..1431f0f 100644
--- a/modules/LightRing_1-0/module.c
+++ b/modules/LightRing_1-0/module.c
@@ -63,6 +63,15 @@ SPIConfig moduleHalSpiLightConfig = {
   /* CR2                         */ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN,
 };
 
+SPIConfig moduleHalSpiWlConfig = {
+  /* circular buffer mode        */ false,
+  /* callback function pointer   */ NULL,
+  /* chip select line port       */ GPIOB,
+  /* chip select line pad number */ GPIOB_WL_SS_N,
+  /* CR1                         */ SPI_CR1_BR_0,
+  /* CR2                         */ SPI_CR2_RXDMAEN | SPI_CR2_TXDMAEN,
+};
+
 /*===========================================================================*/
 /**
  * @name GPIO definitions
diff --git a/modules/LightRing_1-0/module.h b/modules/LightRing_1-0/module.h
index e463279..7252adc 100644
--- a/modules/LightRing_1-0/module.h
+++ b/modules/LightRing_1-0/module.h
@@ -77,6 +77,16 @@ extern SerialConfig moduleHalProgIfConfig;
 extern SPIConfig moduleHalSpiLightConfig;
 
 /**
+ * @brief   SPI interface driver for the wireless transceiver.
+ */
+#define MODULE_HAL_SPI_WL                       SPID2
+
+/**
+ * @brief   Configuration for the SPI interface driver to communicate with the wireless transceiver.
+ */
+extern SPIConfig moduleHalSpiWlConfig;
+
+/**
  * @brief   Real-Time Clock driver.
  */
 #define MODULE_HAL_RTC                          RTCD1
@@ -220,6 +230,7 @@ extern const char* moduleShellPrompt;
   i2cStart(&MODULE_HAL_I2C_EEPROM, &moduleHalI2cEepromConfig);                \
   /* SPI */                                                                   \
   spiStart(&MODULE_HAL_SPI_LIGHT, &moduleHalSpiLightConfig);                  \
+  spiStart(&MODULE_HAL_SPI_WL, &moduleHalSpiWlConfig);                        \
 }
 
 /**
@@ -228,6 +239,7 @@ extern const char* moduleShellPrompt;
 #define MODULE_SHUTDOWN_PERIPHERY_COMM() {                                    \
   /* SPI */                                                                   \
   spiStop(&MODULE_HAL_SPI_LIGHT);                                             \
+  spiStop(&MODULE_HAL_SPI_WL);                                                \
   /* I2C */                                                                   \
   i2cStop(&MODULE_HAL_I2C_EEPROM);                                            \
   /* don't stop the serial driver so messages can still be printed */         \
