altos/stmf0: Add SPI driver.
authorKeith Packard <keithp@keithp.com>
Sun, 3 Apr 2016 02:42:44 +0000 (19:42 -0700)
committerKeith Packard <keithp@keithp.com>
Sun, 3 Apr 2016 02:45:06 +0000 (19:45 -0700)
This also changes the DMA interface a bit so we can select for
interrupts on only the interesting channels.

Signed-off-by: Keith Packard <keithp@keithp.com>
src/stmf0/ao_adc_fast.c
src/stmf0/ao_dma_stm.c
src/stmf0/ao_spi_stm.c [new file with mode: 0644]
src/stmf0/stm32f0.h

index f6740b0e34733d557f745756e81ba8276dd4be9b..0a2e2c5c7b13f952ec5e20ede18132381862d2be 100644 (file)
@@ -72,7 +72,9 @@ _ao_adc_start(void)
                            (1 << STM_DMA_CCR_MINC) |
                            (0 << STM_DMA_CCR_PINC) |
                            (0 << STM_DMA_CCR_CIRC) |
-                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR));
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+
        ao_dma_set_isr(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1), ao_adc_dma_done);
        ao_dma_start(STM_DMA_INDEX(STM_DMA_CHANNEL_ADC_1));
 
index 78fabe18558ea84d43c5ddfe23a3328b9070f766..e90c6bf838b11f4cca1e77df85560f7fe4c344e8 100644 (file)
@@ -28,9 +28,7 @@ static uint8_t ao_dma_allocated[STM_NUM_DMA];
 static uint8_t ao_dma_mutex[STM_NUM_DMA];
 static uint8_t ao_dma_active;
 
-#define id(ch)         STM_DMA_INDEX(ch)
-#define id_mask(id)    (STM_DMA_ISR_MASK << (id))
-#define ch_mask(ch)    id_mask(id(ch))
+#define ch_mask(id)    (STM_DMA_ISR_MASK << STM_DMA_ISR(id))
 
 static void
 ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
@@ -41,7 +39,7 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
        /* Ack them */
        stm_dma.ifcr = isr;
        for (index = low_index; index <= high_index; index++) {
-               if (isr & id_mask(index)) {
+               if (isr & ch_mask(index)) {
                        if (ao_dma_config[index].isr)
                                (*ao_dma_config[index].isr)(index);
                        else {
@@ -52,9 +50,25 @@ ao_dma_isr(uint8_t low_index, uint8_t high_index, uint32_t mask) {
        }
 }
 
-void stm_dma_ch1_isr(void) { ao_dma_isr(id(1), id(1), ch_mask(1)); }
-void stm_dma_ch2_3_isr(void) { ao_dma_isr(id(2), id(3), ch_mask(2) | ch_mask(3)); }
-void stm_dma1_ch4_5_6_isr(void) { ao_dma_isr(id(4), id(6), ch_mask(4) | ch_mask(5) | ch_mask(6)); }
+void stm_dma_ch1_isr(void) {
+       ao_dma_isr(STM_DMA_INDEX(1),
+                  STM_DMA_INDEX(1),
+                  ch_mask(STM_DMA_INDEX(1)));
+}
+
+void stm_dma_ch2_3_isr(void) {
+       ao_dma_isr(STM_DMA_INDEX(2),
+                  STM_DMA_INDEX(3),
+                  ch_mask(STM_DMA_INDEX(2)) |
+                  ch_mask(STM_DMA_INDEX(3)));
+}
+
+void stm_dma1_ch4_5_6_isr(void) {
+       ao_dma_isr(STM_DMA_INDEX(4), STM_DMA_INDEX(6),
+                  ch_mask(STM_DMA_INDEX(4)) |
+                  ch_mask(STM_DMA_INDEX(5)) |
+                  ch_mask(STM_DMA_INDEX(6)));
+}
 
 void
 ao_dma_set_transfer(uint8_t            index,
@@ -73,11 +87,12 @@ ao_dma_set_transfer(uint8_t                 index,
                if (ao_dma_active++ == 0)
                        stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMAEN);
                );
-       stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
+       ao_dma_config[index].isr = NULL;
+       ao_dma_done[index] = 0;
        stm_dma.channel[index].cndtr = count;
        stm_dma.channel[index].cpar = peripheral;
        stm_dma.channel[index].cmar = memory;
-       ao_dma_config[index].isr = NULL;
+       stm_dma.channel[index].ccr = ccr;
 }
 
 void
@@ -89,7 +104,6 @@ ao_dma_set_isr(uint8_t index, void (*isr)(int))
 void
 ao_dma_start(uint8_t index)
 {
-       ao_dma_done[index] = 0;
        stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN);
 }
 
diff --git a/src/stmf0/ao_spi_stm.c b/src/stmf0/ao_spi_stm.c
new file mode 100644 (file)
index 0000000..55bf59d
--- /dev/null
@@ -0,0 +1,478 @@
+/*
+ * Copyright © 2016 Keith Packard <keithp@keithp.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ */
+
+#include <ao.h>
+
+struct ao_spi_stm_info {
+       uint8_t miso_dma_index;
+       uint8_t mosi_dma_index;
+       struct stm_spi *stm_spi;
+};
+
+static uint8_t         ao_spi_mutex[STM_NUM_SPI];
+static uint8_t         ao_spi_index[STM_NUM_SPI];
+
+static const struct ao_spi_stm_info ao_spi_stm_info[STM_NUM_SPI] = {
+       {
+               .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_RX),
+               .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI1_TX),
+               &stm_spi1
+       },
+       {
+               .miso_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_RX),
+               .mosi_dma_index = STM_DMA_INDEX(STM_DMA_CHANNEL_SPI2_TX),
+               &stm_spi2
+       }
+};
+
+static uint8_t spi_dev_null;
+
+
+
+#define SPI_CR2        ((0 << STM_SPI_CR2_LDMA_TX) |                           \
+                (0 << STM_SPI_CR2_LDMA_RX) |                           \
+                (1 << STM_SPI_CR2_FRXTH) |                             \
+                (STM_SPI_CR2_DS_8 << STM_SPI_CR2_DS) |                 \
+                (0 << STM_SPI_CR2_TXEIE) |                             \
+                (0 << STM_SPI_CR2_RXNEIE) |                            \
+                (0 << STM_SPI_CR2_ERRIE) |                             \
+                (STM_SPI_CR2_FRF_MOTOROLA << STM_SPI_CR2_FRF) |        \
+                (0 << STM_SPI_CR2_NSSP) |                              \
+                (0 << STM_SPI_CR2_SSOE))
+
+#define SPI_CR2_DMA    (SPI_CR2 |                      \
+                        (1 << STM_SPI_CR2_TXDMAEN) |   \
+                        (1 << STM_SPI_CR2_RXDMAEN))
+
+#define SPI_CR2_SYNC   (SPI_CR2 |                      \
+                        (0 << STM_SPI_CR2_TXDMAEN) |   \
+                        (0 << STM_SPI_CR2_RXDMAEN))
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+       /* Set up the transmit DMA to deliver data */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           (void *) block,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+                           (0 << STM_DMA_CCR_TCIE));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA -- when this is done, we know the SPI unit
+        * is idle. Without this, we'd have to poll waiting for the BSY bit to
+        * be cleared
+        */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           &spi_dev_null,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+
+       stm_spi->cr2 = SPI_CR2_DMA;
+
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_send_fixed(uint8_t value, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+       /* Set up the transmit DMA to deliver data */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           &value,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+                           (0 << STM_DMA_CCR_TCIE));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA -- when this is done, we know the SPI unit
+        * is idle. Without this, we'd have to poll waiting for the BSY bit to
+        * be cleared
+        */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           &spi_dev_null,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+
+       stm_spi->cr2 = SPI_CR2_DMA;
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_send_sync(void *block, uint16_t len, uint8_t spi_index)
+{
+       uint8_t         *b = block;
+       struct stm_spi  *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+
+       stm_spi->cr2 = SPI_CR2_SYNC;
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       while (len--) {
+               while (!(stm_spi->sr & (1 << STM_SPI_SR_TXE)));
+               stm_spi->dr = *b++;
+       }
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+       spi_dev_null = 0xff;
+
+       /* Set up transmit DMA to make the SPI hardware actually run */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           &spi_dev_null,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (0 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+                           (0 << STM_DMA_CCR_TCIE));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA to capture data */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           block,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+
+       stm_spi->cr2 = SPI_CR2_DMA;
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+
+       /* Wait until the SPI unit is done */
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
+void
+ao_spi_duplex(void *out, void *in, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[AO_SPI_INDEX(spi_index)].miso_dma_index;
+
+       /* Set up transmit DMA to send data */
+       ao_dma_set_transfer(mosi_dma_index,
+                           &stm_spi->dr,
+                           out,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR) |
+                           (0 << STM_DMA_CCR_TCIE));
+
+       /* Clear RXNE */
+       (void) stm_spi->dr;
+
+       /* Set up the receive DMA to capture data */
+       ao_dma_set_transfer(miso_dma_index,
+                           &stm_spi->dr,
+                           in,
+                           len,
+                           (0 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_MEDIUM << STM_DMA_CCR_PL) |
+                           (STM_DMA_CCR_MSIZE_8 << STM_DMA_CCR_MSIZE) |
+                           (STM_DMA_CCR_PSIZE_8 << STM_DMA_CCR_PSIZE) |
+                           (1 << STM_DMA_CCR_MINC) |
+                           (0 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR) |
+                           (1 << STM_DMA_CCR_TCIE));
+
+       stm_spi->cr2 = SPI_CR2_DMA;
+       ao_dma_start(miso_dma_index);
+       ao_dma_start(mosi_dma_index);
+
+       /* Wait until the SPI unit is done */
+       ao_arch_critical(
+               while (!ao_dma_done[miso_dma_index])
+                       ao_sleep(&ao_dma_done[miso_dma_index]);
+               );
+
+       ao_dma_done_transfer(mosi_dma_index);
+       ao_dma_done_transfer(miso_dma_index);
+}
+
+static void
+ao_spi_disable_index(uint8_t spi_index)
+{
+       /* Disable current config
+        */
+       switch (AO_SPI_INDEX(spi_index)) {
+       case STM_SPI_INDEX(1):
+               switch (spi_index) {
+               case AO_SPI_1_PA5_PA6_PA7:
+                       stm_gpio_set(&stm_gpioa, 5, 1);
+                       stm_moder_set(&stm_gpioa, 5, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpioa, 6, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpioa, 7, STM_MODER_OUTPUT);
+                       break;
+               case AO_SPI_1_PB3_PB4_PB5:
+                       stm_gpio_set(&stm_gpiob, 3, 1);
+                       stm_moder_set(&stm_gpiob, 3, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpiob, 4, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpiob, 5, STM_MODER_OUTPUT);
+                       break;
+               }
+               break;
+       case STM_SPI_INDEX(2):
+               switch (spi_index) {
+               case AO_SPI_2_PB13_PB14_PB15:
+                       stm_gpio_set(&stm_gpiob, 13, 1);
+                       stm_moder_set(&stm_gpiob, 13, STM_MODER_OUTPUT);
+                       stm_moder_set(&stm_gpiob, 14, STM_MODER_INPUT);
+                       stm_moder_set(&stm_gpiob, 15, STM_MODER_OUTPUT);
+                       break;
+               }
+               break;
+       }
+}
+
+static void
+ao_spi_enable_index(uint8_t spi_index)
+{
+       switch (AO_SPI_INDEX(spi_index)) {
+       case STM_SPI_INDEX(1):
+               switch (spi_index) {
+               case AO_SPI_1_PA5_PA6_PA7:
+                       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpioa, 6, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpioa, 7, STM_AFR_AF0);
+                       break;
+               case AO_SPI_1_PB3_PB4_PB5:
+                       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF0);
+                       break;
+               }
+               break;
+       case STM_SPI_INDEX(2):
+               switch (spi_index) {
+               case AO_SPI_2_PB13_PB14_PB15:
+                       stm_afr_set(&stm_gpiob, 13, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpiob, 14, STM_AFR_AF0);
+                       stm_afr_set(&stm_gpiob, 15, STM_AFR_AF0);
+                       break;
+               }
+               break;
+       }
+}
+
+static void
+ao_spi_config(uint8_t spi_index, uint32_t speed)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       stm_spi->cr2 = SPI_CR2;
+       stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |                   /* Three wire mode */
+                       (0 << STM_SPI_CR1_BIDIOE) |
+                       (0 << STM_SPI_CR1_CRCEN) |                      /* CRC disabled */
+                       (0 << STM_SPI_CR1_CRCNEXT) |
+                       (0 << STM_SPI_CR1_CRCL) |
+                       (0 << STM_SPI_CR1_RXONLY) |
+                       (1 << STM_SPI_CR1_SSM) |                        /* Software SS handling */
+                       (1 << STM_SPI_CR1_SSI) |                        /*  ... */
+                       (0 << STM_SPI_CR1_LSBFIRST) |                   /* Big endian */
+                       (1 << STM_SPI_CR1_SPE) |                        /* Enable SPI unit */
+                       (speed << STM_SPI_CR1_BR) |                     /* baud rate to pclk/4 */
+                       (1 << STM_SPI_CR1_MSTR) |
+                       (0 << STM_SPI_CR1_CPOL) |                       /* Format 0 */
+                       (0 << STM_SPI_CR1_CPHA));
+
+       if (spi_index != ao_spi_index[id]) {
+
+               /* Disable old config
+                */
+               ao_spi_disable_index(ao_spi_index[id]);
+
+               /* Enable new config
+                */
+               ao_spi_enable_index(spi_index);
+
+               /* Remember current config
+                */
+               ao_spi_index[id] = spi_index;
+       }
+}
+
+uint8_t
+ao_spi_try_get(uint8_t spi_index, uint32_t speed, uint8_t task_id)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+
+       if (!ao_mutex_try(&ao_spi_mutex[id], task_id))
+               return 0;
+       ao_spi_config(spi_index, speed);
+       return 1;
+}
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       ao_mutex_get(&ao_spi_mutex[id]);
+       ao_spi_config(spi_index, speed);
+}
+
+void
+ao_spi_put(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       stm_spi->cr1 = 0;
+       ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+       uint8_t         id = AO_SPI_INDEX(spi_index);
+       struct stm_spi  *stm_spi = ao_spi_stm_info[id].stm_spi;
+
+       ao_spi_disable_index(spi_index);
+
+       stm_spi->cr1 = 0;
+       (void) stm_spi->sr;
+       stm_spi->cr2 = SPI_CR2_SYNC;
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_1
+# if SPI_1_PA5_PA6_PA7
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPAEN);
+       stm_ospeedr_set(&stm_gpioa, 5, SPI_1_OSPEEDR);
+       stm_ospeedr_set(&stm_gpioa, 6, SPI_1_OSPEEDR);
+       stm_ospeedr_set(&stm_gpioa, 7, SPI_1_OSPEEDR);
+# endif
+# if SPI_1_PB3_PB4_PB5
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+       stm_ospeedr_set(&stm_gpiob, 3, SPI_1_OSPEEDR);
+       stm_ospeedr_set(&stm_gpiob, 4, SPI_1_OSPEEDR);
+       stm_ospeedr_set(&stm_gpiob, 5, SPI_1_OSPEEDR);
+# endif
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+       ao_spi_index[0] = AO_SPI_CONFIG_NONE;
+       ao_spi_channel_init(STM_SPI_INDEX(1));
+#endif
+
+#if HAS_SPI_2
+# if SPI_2_PB10_PB13_PB14
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_IOPBEN);
+       stm_ospeedr_set(&stm_gpiob, 13, SPI_2_OSPEEDR);
+       stm_ospeedr_set(&stm_gpiob, 14, SPI_2_OSPEEDR);
+       stm_ospeedr_set(&stm_gpiob, 15, SPI_2_OSPEEDR);
+# endif
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+       ao_spi_index[1] = AO_SPI_CONFIG_NONE;
+       ao_spi_channel_init(STM_SPI_INDEX(2));
+#endif
+}
index ce8ca456d66d2660d7e073f4e3e93db9256d8ccb..14be5fbbd7ef0f09ee567da6def0504de505a430 100644 (file)
@@ -795,7 +795,7 @@ isr(tim7)
 #define STM_ISR_TSC_POS                        8
 #define STM_ISR_DMA_CH1_POS            9
 #define STM_ISR_DMA_CH2_3_DMA2_CH1_2_POS       10
-#define STM_ISR_DMA_CH44_5_6_7_DMA2_CH3_4_5_POS        11
+#define STM_ISR_DMA_CH4_5_6_7_DMA2_CH3_4_5_POS 11
 #define STM_ISR_ADC_COMP_POS           12
 #define STM_ISR_TIM1_BRK_UP_TRG_COM_POS        13
 #define STM_ISR_TIM1_CC_POS            14
@@ -890,7 +890,7 @@ struct stm_dma_channel {
        vuint32_t       reserved;
 };
 
-#define STM_NUM_DMA    6
+#define STM_NUM_DMA    5
 
 struct stm_dma {
        vuint32_t               isr;
@@ -900,7 +900,7 @@ struct stm_dma {
 
 extern struct stm_dma stm_dma;
 
-/* DMA channels go from 1 to 6, instead of 0 to 5 (sigh)
+/* DMA channels go from 1 to 5, instead of 0 to 4 (sigh)
  */
 
 #define STM_DMA_INDEX(channel)         ((channel) - 1)
@@ -1042,7 +1042,7 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
 #define STM_SPI_CR1_BIDIOE             14
 #define STM_SPI_CR1_CRCEN              13
 #define STM_SPI_CR1_CRCNEXT            12
-#define STM_SPI_CR1_DFF                        11
+#define STM_SPI_CR1_CRCL               11
 #define STM_SPI_CR1_RXONLY             10
 #define STM_SPI_CR1_SSM                        9
 #define STM_SPI_CR1_SSI                        8
@@ -1063,17 +1063,43 @@ extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
 #define STM_SPI_CR1_CPOL               1
 #define STM_SPI_CR1_CPHA               0
 
+#define STM_SPI_CR2_LDMA_TX    14
+#define STM_SPI_CR2_LDMA_RX    13
+#define STM_SPI_CR2_FRXTH      12
+#define STM_SPI_CR2_DS         8
+#define  STM_SPI_CR2_DS_4              0x3
+#define  STM_SPI_CR2_DS_5              0x4
+#define  STM_SPI_CR2_DS_6              0x5
+#define  STM_SPI_CR2_DS_7              0x6
+#define  STM_SPI_CR2_DS_8              0x7
+#define  STM_SPI_CR2_DS_9              0x8
+#define  STM_SPI_CR2_DS_10             0x9
+#define  STM_SPI_CR2_DS_11             0xa
+#define  STM_SPI_CR2_DS_12             0xb
+#define  STM_SPI_CR2_DS_13             0xc
+#define  STM_SPI_CR2_DS_14             0xd
+#define  STM_SPI_CR2_DS_15             0xe
+#define  STM_SPI_CR2_DS_16             0xf
 #define STM_SPI_CR2_TXEIE      7
 #define STM_SPI_CR2_RXNEIE     6
 #define STM_SPI_CR2_ERRIE      5
+#define STM_SPI_CR2_FRF                4
+# define STM_SPI_CR2_FRF_MOTOROLA      0
+# define STM_SPI_CR2_FRF_TI            1
+#define STM_SPI_CR2_NSSP       3
 #define STM_SPI_CR2_SSOE       2
 #define STM_SPI_CR2_TXDMAEN    1
 #define STM_SPI_CR2_RXDMAEN    0
 
+#define STM_SPI_SR_FTLVL       11
+#define STM_SPI_SR_FRLVL       9
+#define STM_SPI_SR_FRE         8
 #define STM_SPI_SR_BSY         7
 #define STM_SPI_SR_OVR         6
 #define STM_SPI_SR_MODF                5
 #define STM_SPI_SR_CRCERR      4
+#define STM_SPI_SR_UDR         3
+#define STM_SPI_SR_CHSIDE      2
 #define STM_SPI_SR_TXE         1
 #define STM_SPI_SR_RXNE                0