altos: Add DMA, SPI and MS5607 drivers
authorKeith Packard <keithp@keithp.com>
Sat, 7 Apr 2012 01:07:07 +0000 (18:07 -0700)
committerKeith Packard <keithp@keithp.com>
Sat, 7 Apr 2012 01:07:07 +0000 (18:07 -0700)
Signed-off-by: Keith Packard <keithp@keithp.com>
13 files changed:
src/core/ao.h
src/drivers/ao_ms5607.c [new file with mode: 0644]
src/drivers/ao_ms5607.h [new file with mode: 0644]
src/megametrum-v0.1/Makefile
src/megametrum-v0.1/ao_megametrum.c
src/megametrum-v0.1/ao_pins.h
src/stm-demo/Makefile
src/stm-demo/ao_demo.c
src/stm-demo/ao_pins.h
src/stm/ao_arch_funcs.h
src/stm/ao_dma_stm.c [new file with mode: 0644]
src/stm/ao_spi_stm.c [new file with mode: 0644]
src/stm/stm32l.h

index 080cadb2646dee8b1b5a1c317842097d5ff82e71..67efa437f843fbe91143041ae7623c8bc8b49da8 100644 (file)
@@ -114,6 +114,7 @@ ao_start_scheduler(void);
 #define AO_PANIC_USB           10      /* Trying to send USB packet while busy */
 #define AO_PANIC_BT            11      /* Communications with bluetooth device failed */
 #define AO_PANIC_STACK         12      /* Stack overflow */
+#define AO_PANIC_SPI           13      /* SPI communication failure */
 
 /* Stop the operating system, beeping and blinking the reason */
 void
@@ -1895,4 +1896,10 @@ int32_t ao_freq_to_set(int32_t freq, int32_t cal);
 
 #include <ao_arch_funcs.h>
 
+/*
+ * ao_ms5607.c
+ */
+
+void ao_ms5607_init(void);
+
 #endif /* _AO_H_ */
diff --git a/src/drivers/ao_ms5607.c b/src/drivers/ao_ms5607.c
new file mode 100644 (file)
index 0000000..970fea1
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+ * Copyright © 2012 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>
+#include "ao_ms5607.h"
+
+#define AO_MS5607_CS_GPIO      stm_gpioc
+#define AO_MS5607_CS           4
+#define AO_MS5607_CS_MASK      (1 << AO_MS5607_CS)
+#define AO_MS5607_SPI_INDEX    (STM_SPI_INDEX(1))
+
+struct ms5607_prom {
+       uint16_t        reserved;
+       uint16_t        sens;
+       uint16_t        off;
+       uint16_t        tcs;
+       uint16_t        tco;
+       uint16_t        tref;
+       uint16_t        tempsens;
+       uint16_t        crc;
+};
+
+static struct ms5607_prom ms5607_prom;
+
+static void
+ao_ms5607_start(void) {
+       ao_spi_get(AO_MS5607_SPI_INDEX);
+       stm_gpio_set(&AO_MS5607_CS_GPIO, AO_MS5607_CS, 0);
+}
+
+static void
+ao_ms5607_stop(void) {
+       stm_gpio_set(&AO_MS5607_CS_GPIO, AO_MS5607_CS, 1);
+       ao_spi_put(AO_MS5607_SPI_INDEX);
+}
+
+static void
+ao_ms5607_reset(void) {
+       uint8_t cmd;
+
+       cmd = AO_MS5607_RESET;
+       ao_ms5607_start();
+       ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+       ao_ms5607_stop();
+}
+
+static uint16_t
+ao_ms5607_prom_read(uint8_t addr)
+{
+       uint8_t cmd = AO_MS5607_PROM_READ(addr);
+       uint8_t d[2];
+
+       ao_ms5607_start();
+       ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+       ao_spi_recv(d, 2, AO_MS5607_SPI_INDEX);
+       ao_ms5607_stop();
+       return ((uint16_t) d[0] << 8) | (uint16_t) d[1];
+}
+
+static void
+ao_ms5607_init_chip(void) {
+       uint8_t         addr;
+       uint16_t        *prom;
+       ao_ms5607_reset();
+       prom = &ms5607_prom.reserved;
+
+       for (addr = 0; addr <= 7; addr++)
+               prom[addr] = ao_ms5607_prom_read(addr);
+}
+
+static uint32_t
+ao_ms5607_convert(uint8_t cmd) {
+       uint8_t reply[3];
+       uint8_t read;
+
+       ao_ms5607_start();
+       ao_spi_send(&cmd, 1, AO_MS5607_SPI_INDEX);
+       ao_ms5607_stop();
+
+       ao_delay(AO_MS_TO_TICKS(200));
+
+       ao_ms5607_start();
+       read = AO_MS5607_ADC_READ;
+       ao_spi_send(&read, 1, AO_MS5607_SPI_INDEX);
+       ao_spi_recv(&reply, 3, AO_MS5607_SPI_INDEX);
+       ao_ms5607_stop();
+
+       return ((uint32_t) reply[0] << 16) | ((uint32_t) reply[1] << 8) | (uint32_t) reply[2];
+}
+
+static void
+ao_ms5607_dump(void)
+{
+       uint8_t addr;
+       uint32_t d1, d2;
+       int32_t dT;
+       int32_t TEMP;
+       int64_t OFF;
+       int64_t SENS;
+       int32_t P;
+
+       ao_ms5607_init_chip();
+       printf ("reserved: %d\n", ms5607_prom.reserved);
+       printf ("sens:     %d\n", ms5607_prom.sens);
+       printf ("off:      %d\n", ms5607_prom.off);
+       printf ("tcs:      %d\n", ms5607_prom.tcs);
+       printf ("tco:      %d\n", ms5607_prom.tco);
+       printf ("tref:     %d\n", ms5607_prom.tref);
+       printf ("tempsens: %d\n", ms5607_prom.tempsens);
+       printf ("crc:      %d\n", ms5607_prom.crc);
+       d1 =  ao_ms5607_convert(AO_MS5607_CONVERT_D1_4096);
+       printf ("Conversion D1: %d\n", d1);
+       d2 =  ao_ms5607_convert(AO_MS5607_CONVERT_D2_4096);
+       printf ("Conversion D2: %d\n", d2);
+
+       dT = d2 - ((int32_t) ms5607_prom.tref << 8);
+       
+       TEMP = 2000 + (((int64_t) dT * ms5607_prom.tempsens) >> 23);
+
+       OFF = ((int64_t) ms5607_prom.off << 17) + (((int64_t) ms5607_prom.tco * dT) >> 6);
+
+       SENS = ((int64_t) ms5607_prom.sens << 16) + (((int64_t) ms5607_prom.tcs * dT) >> 7);
+
+       if (TEMP < 2000) {
+               int32_t T2 = ((int64_t) dT * (int64_t) dT) >> 31;
+               int32_t TEMPM = TEMP - 2000;
+               int64_t OFF2 = (61 * (int64_t) TEMPM * (int64_t) TEMPM) >> 4;
+               int64_t SENS2 = 2 * (int64_t) TEMPM * (int64_t) TEMPM;
+       }
+
+       P = ((((int64_t) d1 * SENS) >> 21) - OFF) >> 15;
+       
+       printf ("Temperature: %d", TEMP);
+       printf ("Pressure %d\n", P);
+}
+
+__code struct ao_cmds ao_ms5607_cmds[] = {
+       { ao_ms5607_dump,       "p\0Display MS5607 data" },
+       { 0, NULL },
+};
+
+void
+ao_ms5607_init(void)
+{
+       ao_cmd_register(&ao_ms5607_cmds[0]);
+
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
+       stm_gpio_set(&AO_MS5607_CS_GPIO, AO_MS5607_CS, 1);
+       stm_moder_set(&AO_MS5607_CS_GPIO, AO_MS5607_CS, STM_MODER_OUTPUT);
+}
diff --git a/src/drivers/ao_ms5607.h b/src/drivers/ao_ms5607.h
new file mode 100644 (file)
index 0000000..6c24536
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#ifndef _AO_MS5607_H_
+#define _AO_MS5607_H_
+
+#define AO_MS5607_RESET                        0x1e
+
+#define AO_MS5607_CONVERT_D1_256       0x40
+#define AO_MS5607_CONVERT_D1_512       0x42
+#define AO_MS5607_CONVERT_D1_1024      0x44
+#define AO_MS5607_CONVERT_D1_2048      0x46
+#define AO_MS5607_CONVERT_D1_4096      0x48
+
+#define AO_MS5607_CONVERT_D2_256       0x50
+#define AO_MS5607_CONVERT_D2_512       0x52
+#define AO_MS5607_CONVERT_D2_1024      0x54
+#define AO_MS5607_CONVERT_D2_2048      0x56
+#define AO_MS5607_CONVERT_D2_4096      0x58
+
+#define AO_MS5607_ADC_READ             0x00
+#define AO_MS5607_PROM_READ(ad)                0xA0 | ((ad) << 1)
+
+#endif /* _AO_MS5607_H_ */
index 23160d9b0622452152c6e9d6c75b53c8facfae8a..fbcb4a57f8985176c43f6cf39f39eaa2c4ba83d5 100644 (file)
@@ -31,13 +31,16 @@ ALTOS_SRC = \
        ao_serial_stm.c \
        ao_gps_skytraq.c \
        ao_cc1120.c \
-       ao_freq.c
+       ao_freq.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c \
+       ao_ms5607.c
 
 PRODUCT=MegaMetrum-v0.1
 PRODUCT_DEF=-DMEGAMETRUM
 IDPRODUCT=0x000a
 
-CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -Os -g
+CFLAGS = $(PRODUCT_DEF) $(STM_CFLAGS) -O0 -g
 
 PROG=megametrum-v0.1-$(VERSION).elf
 
index 6bf43cb11307d5bb1bd8a1a64fba65715e582d51..0d88f4c1319164d85123ce915d5b2a6824611466 100644 (file)
@@ -29,6 +29,9 @@ main(void)
        ao_cmd_init();
        ao_gps_init();
        ao_config_init();
+       ao_dma_init();
+       ao_spi_init();
+       ao_ms5607_init();
        
        ao_start_scheduler();
        return 0;
index dadeb3801ff238a03713bf89bb175bc44852bdba..ee4510e65c55ae92edc36a0c962d3b4f0800c968 100644 (file)
 #define HAS_BEEP               0
 
 #define HAS_SPI_1              1
-#define SPI_1_PE13_PE14_PE15   1
+#define SPI_1_PA5_PA6_PA7      1
+#define SPI_1_PB3_PB4_PB5      0
+#define SPI_1_PE13_PE14_PE15   0
 
 #define HAS_SPI_2              1
 #define SPI_2_PB13_PB14_PB15   1
+#define SPI_2_PD1_PD3_PD4      0
 
 #define HAS_I2C_1              1
 #define I2C_1_PB8_PB9          1
index 366291c6e079306f18dec5c68b1b86b6ec9ebe59..c1f4937112b8c5edfd32562468b511cefb1f0be0 100644 (file)
@@ -26,7 +26,10 @@ ALTOS_SRC = \
        ao_timer.c \
        ao_serial_stm.c \
        ao_lcd_stm.c \
-       ao_lcd_font.c
+       ao_lcd_font.c \
+       ao_mutex.c \
+       ao_dma_stm.c \
+       ao_spi_stm.c 
 
 PRODUCT=StmDemo-v0.0
 PRODUCT_DEF=-DSTM_DEMO
index 544f261fcbe7be64fbbfe05e055a6b592e2fee7d..54f7c8f2efb72f46dd5cb93a9bbc1327c791c7a8 100644 (file)
@@ -50,6 +50,71 @@ void _lseek() { }
 void _exit () { }
 void _read () { }
 void _fstat() { }
+
+static void
+ao_dma_test(void) {
+       static char     src[20] = "hello, world";
+       static char     dst[20];
+       
+       dst[0] = '\0';
+       ao_dma_set_transfer(STM_DMA_INDEX(1), dst, src, 13,
+                           (1 << STM_DMA_CCR_MEM2MEM) |
+                           (STM_DMA_CCR_PL_LOW << 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) |
+                           (1 << STM_DMA_CCR_PINC) |
+                           (0 << STM_DMA_CCR_CIRC) |
+                           (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR));
+       ao_dma_start(STM_DMA_INDEX(1));
+       cli();
+       while (!ao_dma_done[STM_DMA_INDEX(1)])
+               ao_sleep(&ao_dma_done[STM_DMA_INDEX(1)]);
+       sei();
+       printf ("copied %s\n", dst);
+}
+
+static void
+ao_spi_write(void) {
+       unsigned char   data[] = { 0x55, 0xaa, 0xff, 0x00 };
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               ao_spi_get(0);
+               stm_gpio_set(&stm_gpioc, 12, 0);
+               ao_spi_send(data, 1, 0);
+               stm_gpio_set(&stm_gpioc, 12, 1);
+               ao_spi_put(0);
+               printf(".");
+               flush();
+               ao_delay(100);
+       }
+}
+
+static void
+ao_spi_read(void) {
+       unsigned char   data[4];
+       int i;
+
+       for (i = 0; i < 10; i++) {
+               ao_spi_get(0);
+               stm_gpio_set(&stm_gpioc, 12, 0);
+               ao_spi_recv(data, 4, 0);
+               printf(".");
+               flush();
+               stm_gpio_set(&stm_gpioc, 12, 1);
+               ao_spi_put(0);
+               ao_delay(100);
+       }
+}
+
+__code struct ao_cmds ao_demo_cmds[] = {
+       { ao_dma_test,  "D\0DMA test" },
+       { ao_spi_write, "W\0SPI write" },
+       { ao_spi_read, "R\0SPI read" },
+       { 0, NULL }
+};
+
 int
 main(void)
 {
@@ -57,11 +122,19 @@ main(void)
        
        ao_serial_init();
        ao_timer_init();
+       ao_dma_init();
        ao_cmd_init();
-       ao_lcd_stm_init();
-       ao_lcd_font_init();
-       ao_add_task(&demo_task, ao_demo, "demo");
+//     ao_lcd_stm_init();
+//     ao_lcd_font_init();
+       ao_spi_init();
+
+       ao_cmd_register(&ao_demo_cmds[0]);
        
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOCEN);
+       stm_gpio_set(&stm_gpioc, 12, 1);
+       stm_moder_set(&stm_gpioc, 12, STM_MODER_OUTPUT);
+       stm_otyper_set(&stm_gpioc, 12, STM_OTYPER_PUSH_PULL);
+
        ao_start_scheduler();
        return 0;
 }
index 798a292e38c2d3835583635f4a4a66e36b7801af..09c88f9054aa3a35b6fba672a981a03ad0ae1778 100644 (file)
 #define SERIAL_3_PC10_PC11     0
 #define SERIAL_3_PD8_PD9       1
 
+#define HAS_SPI_1              1
+#define SPI_1_PB3_PB4_PB5      1
+
+#define HAS_SPI_2              0
+
 #define HAS_USB                        0
 #define HAS_BEEP               0
 #define PACKET_HAS_SLAVE       0
index 9b68f19a0c06dbd5889a0c1e7bb1e139255e8e4c..29e3f42f069a368e2dac1ed353523cd6a774679b 100644 (file)
@@ -18,6 +18,8 @@
 #ifndef _AO_ARCH_FUNCS_H_
 #define _AO_ARCH_FUNCS_H_
 
+/* ao_spi_stm.c
+ */
 extern uint8_t ao_spi_mutex[STM_NUM_SPI];
 
 static inline void ao_spi_get(uint8_t spi_index) { ao_mutex_get(&ao_spi_mutex[spi_index]); }
@@ -30,6 +32,30 @@ void
 ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
 
 void
-ao_spi_init(uint8_t spi_index);
+ao_spi_init(void);
+
+/* ao_dma_stm.c
+ */
+
+extern uint8_t ao_dma_done[STM_NUM_DMA];
+
+void
+ao_dma_set_transfer(uint8_t            index,
+                   volatile void       *peripheral,
+                   void                *memory,
+                   uint16_t            count,
+                   uint32_t            ccr);
+
+void
+ao_dma_start(uint8_t index);
+
+void
+ao_dma_done_transfer(uint8_t index);
+
+void
+ao_dma_abort(uint8_t index);
+
+void
+ao_dma_init(void);
 
 #endif /* _AO_ARCH_FUNCS_H_ */
diff --git a/src/stm/ao_dma_stm.c b/src/stm/ao_dma_stm.c
new file mode 100644 (file)
index 0000000..70b9e48
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2012 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"
+
+#define NUM_DMA        7
+
+struct ao_dma_config {
+       uint32_t        isr;
+};
+
+uint8_t ao_dma_done[NUM_DMA];
+
+static struct ao_dma_config ao_dma_config[NUM_DMA];
+static uint8_t ao_dma_mutex[NUM_DMA];
+
+static void
+ao_dma_isr(uint8_t index) {
+       /* Get channel interrupt bits */
+       uint32_t        isr = stm_dma.isr & (STM_DMA_ISR_MASK <<
+                                            STM_DMA_ISR(index));
+
+       /* Ack them */
+       stm_dma.ifcr = isr;
+       isr >>= STM_DMA_ISR(index);
+       ao_dma_config[index].isr |= isr;
+       ao_dma_done[index] = 1;
+       ao_wakeup(&ao_dma_done[index]);
+}
+
+void stm_dma1_channel1_isr(void) { ao_dma_isr(STM_DMA_INDEX(1)); }
+void stm_dma1_channel2_isr(void) { ao_dma_isr(STM_DMA_INDEX(2)); }
+void stm_dma1_channel3_isr(void) { ao_dma_isr(STM_DMA_INDEX(3)); }
+void stm_dma1_channel4_isr(void) { ao_dma_isr(STM_DMA_INDEX(4)); }
+void stm_dma1_channel5_isr(void) { ao_dma_isr(STM_DMA_INDEX(5)); }
+void stm_dma1_channel6_isr(void) { ao_dma_isr(STM_DMA_INDEX(6)); }
+void stm_dma1_channel7_isr(void) { ao_dma_isr(STM_DMA_INDEX(7)); }
+
+void
+ao_dma_set_transfer(uint8_t            index,
+                   volatile void       *peripheral,
+                   void                *memory,
+                   uint16_t            count,
+                   uint32_t            ccr)
+{
+       ao_mutex_get(&ao_dma_mutex[index]);
+       stm_dma.channel[index].ccr = ccr | (1 << STM_DMA_CCR_TCIE);
+       stm_dma.channel[index].cndtr = count;
+       stm_dma.channel[index].cpar = (uint32_t) peripheral;
+       stm_dma.channel[index].cmar = (uint32_t) memory;
+}
+
+void
+ao_dma_start(uint8_t index)
+{
+       ao_dma_done[index] = 0;
+       stm_dma.channel[index].ccr |= (1 << STM_DMA_CCR_EN);
+}
+
+void
+ao_dma_done_transfer(uint8_t index)
+{
+       stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
+       ao_mutex_put(&ao_dma_mutex[index]);
+}
+
+void
+ao_dma_abort(uint8_t index)
+{
+       stm_dma.channel[index].ccr &= ~(1 << STM_DMA_CCR_EN);
+}
+
+void
+ao_dma_init(void)
+{
+       int     index;
+
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_DMA1EN);
+
+       for (index = 0; index < STM_NUM_DMA; index++) {
+               stm_nvic_set_enable(STM_ISR_DMA1_CHANNEL1_POS + index);
+               stm_nvic_set_priority(STM_ISR_DMA1_CHANNEL1_POS + index, 4);
+       }
+       
+}
diff --git a/src/stm/ao_spi_stm.c b/src/stm/ao_spi_stm.c
new file mode 100644 (file)
index 0000000..da04302
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright © 2012 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;
+};
+
+uint8_t        ao_spi_mutex[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;
+
+void
+ao_spi_send(void *block, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
+       uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
+
+       ao_dma_set_transfer(mosi_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_MEM_TO_PER << STM_DMA_CCR_DIR));
+       /* Clear any stale data */
+       (void) stm_spi->dr;
+       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));
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (1 << STM_SPI_CR2_RXDMAEN));
+       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_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+       struct stm_spi *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
+#if 0
+       uint8_t *d = block;
+
+       while (len--) {
+               stm_spi->dr = 0xff;
+               while (!(stm_spi->sr & (1 << STM_SPI_SR_RXNE)));
+               *d++ = stm_spi->dr;
+       }
+       while (stm_spi->sr & (1 << STM_SPI_SR_BSY));
+#else
+       uint8_t mosi_dma_index = ao_spi_stm_info[spi_index].mosi_dma_index;
+       uint8_t miso_dma_index = ao_spi_stm_info[spi_index].miso_dma_index;
+
+       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));
+       /* Clear any stale data */
+       (void) stm_spi->dr;
+       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));
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (1 << STM_SPI_CR2_TXDMAEN) |
+                       (1 << STM_SPI_CR2_RXDMAEN));
+       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);
+#endif
+}
+
+static void
+ao_spi_channel_init(uint8_t spi_index)
+{
+       struct stm_spi  *stm_spi = ao_spi_stm_info[spi_index].stm_spi;
+
+       stm_spi->cr1 = 0;
+       (void) stm_spi->sr;
+       stm_spi->cr1 = ((0 << STM_SPI_CR1_BIDIMODE) |
+                       (0 << STM_SPI_CR1_BIDIOE) |
+                       (0 << STM_SPI_CR1_CRCEN) |
+                       (0 << STM_SPI_CR1_CRCNEXT) |
+                       (0 << STM_SPI_CR1_DFF) |
+                       (0 << STM_SPI_CR1_RXONLY) |
+                       (1 << STM_SPI_CR1_SSM) |
+                       (1 << STM_SPI_CR1_SSI) |
+                       (0 << STM_SPI_CR1_LSBFIRST) |
+                       (1 << STM_SPI_CR1_SPE) |
+                       (STM_SPI_CR1_BR_PCLK_4 << STM_SPI_CR1_BR) |
+                       (1 << STM_SPI_CR1_MSTR) |
+                       (0 << STM_SPI_CR1_CPOL) |
+                       (0 << STM_SPI_CR1_CPHA));
+       stm_spi->cr2 = ((0 << STM_SPI_CR2_TXEIE) |
+                       (0 << STM_SPI_CR2_RXNEIE) |
+                       (0 << STM_SPI_CR2_ERRIE) |
+                       (0 << STM_SPI_CR2_SSOE) |
+                       (0 << STM_SPI_CR2_TXDMAEN) |
+                       (0 << STM_SPI_CR2_RXDMAEN));
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_1
+# if SPI_1_PA5_PA6_PA7
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOAEN);
+       stm_afr_set(&stm_gpioa, 5, STM_AFR_AF5);
+       stm_afr_set(&stm_gpioa, 6, STM_AFR_AF5);
+       stm_afr_set(&stm_gpioa, 7, STM_AFR_AF5);
+# else
+#  if SPI_1_PB3_PB4_PB5
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+       stm_afr_set(&stm_gpiob, 3, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiob, 4, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiob, 5, STM_AFR_AF5);
+#  else
+#   if SPI_1_PE13_PE14_PE15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOEEN);
+       stm_afr_set(&stm_gpioe, 13, STM_AFR_AF5);
+       stm_afr_set(&stm_gpioe, 14, STM_AFR_AF5);
+       stm_afr_set(&stm_gpioe, 15, STM_AFR_AF5);
+#   else
+#    error "No SPI_1 port configuration specified"
+#   endif
+#  endif
+# endif
+
+       stm_rcc.apb2enr |= (1 << STM_RCC_APB2ENR_SPI1EN);
+
+       ao_spi_channel_init(0);
+
+       stm_nvic_set_enable(STM_ISR_SPI1_POS);
+       stm_nvic_set_priority(STM_ISR_SPI1_POS, 3);
+#endif
+
+#if HAS_SPI_2
+# if SPI_2_PB13_PB14_PB15
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN);
+       stm_afr_set(&stm_gpiob, 13, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiob, 14, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiob, 15, STM_AFR_AF5);
+# else
+#  if SPI_2_PPD1_PD3_PD4
+       stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIODEN);
+       stm_afr_set(&stm_gpiod, 1, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiod, 3, STM_AFR_AF5);
+       stm_afr_set(&stm_gpiod, 4, STM_AFR_AF5);
+#  else
+#   error "No SPI_2 port configuration specified"
+#  endif
+# endif
+
+       stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_SPI2EN);
+
+       ao_spi_channel_init(1);
+
+       stm_nvic_set_enable(STM_ISR_SPI2_POS);
+       stm_nvic_set_priority(STM_ISR_SPI2_POS, 3);
+#endif
+}
index 531a4fb9488c026e899ea48375bc4ca6c3048660..b40ec0eeb49bff868553a284471fe14f26dbb321 100644 (file)
@@ -159,6 +159,17 @@ stm_afr_get(struct stm_gpio *gpio, int pin) {
        }
 }
 
+static inline void
+stm_gpio_set(struct stm_gpio *gpio, int pin, uint8_t value) {
+       /* Use the bit set/reset register to do this atomically */
+       gpio->bsrr = ((uint32_t) (value ^ 1) << (pin + 16)) | ((uint32_t) value << pin);
+}
+
+static inline uint8_t
+stm_gpio_isset(struct stm_gpio *gpio, int pin) {
+       return (gpio->idr >> pin) & 1;
+}
+
 extern struct stm_gpio stm_gpioa;
 extern struct stm_gpio stm_gpiob;
 extern struct stm_gpio stm_gpioc;
@@ -238,11 +249,6 @@ extern struct stm_usart stm_usart3;
 #define STM_USART_CR3_IREN     (1)     /* IrDA mode enable */
 #define STM_USART_CR3_EIE      (0)     /* Error interrupt enable */
 
-struct stm_spi {
-};
-
-extern struct stm_spi stm_spi1;
-
 struct stm_tim {
 };
 
@@ -842,4 +848,168 @@ isr(tim7)
 #define STM_ISR_TIM6_POS               43
 #define STM_ISR_TIM7_POS               44
 
+struct stm_dma_channel {
+       vuint32_t       ccr;
+       vuint32_t       cndtr;
+       vuint32_t       cpar;
+       vuint32_t       cmar;
+       vuint32_t       reserved;
+};
+
+#define STM_NUM_DMA    7
+
+struct stm_dma {
+       vuint32_t               isr;
+       vuint32_t               ifcr;
+       struct stm_dma_channel  channel[STM_NUM_DMA];
+};
+
+extern struct stm_dma stm_dma;
+
+/* DMA channels go from 1 to 7, instead of 0 to 6 (sigh)
+ */
+
+#define STM_DMA_INDEX(channel)         ((channel) - 1)
+
+#define STM_DMA_ISR(index)             ((index) << 2)
+#define STM_DMA_ISR_MASK                       0xf
+#define STM_DMA_ISR_TEIF                       3
+#define STM_DMA_ISR_HTIF                       2
+#define STM_DMA_ISR_TCIF                       1
+#define STM_DMA_ISR_GIF                                0
+
+#define STM_DMA_IFCR(index)            ((index) << 2)
+#define STM_DMA_IFCR_MASK                      0xf
+#define STM_DMA_IFCR_CTEIF                     3
+#define STM_DMA_IFCR_CHTIF                     2
+#define STM_DMA_IFCR_CTCIF                     1
+#define STM_DMA_IFCR_CGIF                      0
+
+#define STM_DMA_CCR_MEM2MEM            (14)
+
+#define STM_DMA_CCR_PL                 (12)
+#define  STM_DMA_CCR_PL_LOW                    (0)
+#define  STM_DMA_CCR_PL_MEDIUM                 (1)
+#define  STM_DMA_CCR_PL_HIGH                   (2)
+#define  STM_DMA_CCR_PL_VERY_HIGH              (3)
+#define  STM_DMA_CCR_PL_MASK                   (3)
+
+#define STM_DMA_CCR_MSIZE              (10)
+#define  STM_DMA_CCR_MSIZE_8                   (0)
+#define  STM_DMA_CCR_MSIZE_16                  (1)
+#define  STM_DMA_CCR_MSIZE_32                  (2)
+#define  STM_DMA_CCR_MSIZE_MASK                        (3)
+
+#define STM_DMA_CCR_PSIZE              (8)
+#define  STM_DMA_CCR_PSIZE_8                   (0)
+#define  STM_DMA_CCR_PSIZE_16                  (1)
+#define  STM_DMA_CCR_PSIZE_32                  (2)
+#define  STM_DMA_CCR_PSIZE_MASK                        (3)
+
+#define STM_DMA_CCR_MINC               (7)
+#define STM_DMA_CCR_PINC               (6)
+#define STM_DMA_CCR_CIRC               (5)
+#define STM_DMA_CCR_DIR                        (4)
+#define  STM_DMA_CCR_DIR_PER_TO_MEM            0
+#define  STM_DMA_CCR_DIR_MEM_TO_PER            1
+#define STM_DMA_CCR_TEIE               (3)
+#define STM_DMA_CCR_HTIE               (2)
+#define STM_DMA_CCR_TCIE               (1)
+#define STM_DMA_CCR_EN                 (0)
+
+#define STM_DMA_CHANNEL_ADC1           1
+#define STM_DMA_CHANNEL_SPI1_RX                2
+#define STM_DMA_CHANNEL_SPI1_TX                3
+#define STM_DMA_CHANNEL_SPI2_RX                4
+#define STM_DMA_CHANNEL_SPI2_TX                5
+#define STM_DMA_CHANNEL_USART3_TX      2
+#define STM_DMA_CHANNEL_USART3_RX      3
+#define STM_DMA_CHANNEL_USART1_TX      4
+#define STM_DMA_CHANNEL_USART1_RX      5
+#define STM_DMA_CHANNEL_USART2_RX      6
+#define STM_DMA_CHANNEL_USART2_TX      7
+#define STM_DMA_CHANNEL_I2C2_TX                4
+#define STM_DMA_CHANNEL_I2C2_RX                5
+#define STM_DMA_CHANNEL_I2C1_RX                6
+#define STM_DMA_CHANNEL_I2C1_TX                7
+#define STM_DMA_CHANNEL_TIM2_CH3       1
+#define STM_DMA_CHANNEL_TIM2_UP                2
+#define STM_DMA_CHANNEL_TIM2_CH1       5
+#define STM_DMA_CHANNEL_TIM2_CH2       7
+#define STM_DMA_CHANNEL_TIM2_CH4       7
+#define STM_DMA_CHANNEL_TIM3_CH3       2
+#define STM_DMA_CHANNEL_TIM3_CH4       3
+#define STM_DMA_CHANNEL_TIM3_UP                3
+#define STM_DMA_CHANNEL_TIM3_CH1       6
+#define STM_DMA_CHANNEL_TIM3_TRIG      6
+#define STM_DMA_CHANNEL_TIM4_CH1       1
+#define STM_DMA_CHANNEL_TIM4_CH2       4
+#define STM_DMA_CHANNEL_TIM4_CH3       5
+#define STM_DMA_CHANNEL_TIM4_UP                7
+#define STM_DMA_CHANNEL_TIM6_UP_DA     2
+#define STM_DMA_CHANNEL_C_CHANNEL1     2
+#define STM_DMA_CHANNEL_TIM7_UP_DA     3
+#define STM_DMA_CHANNEL_C_CHANNEL2     3
+
+/*
+ * Only spi channel 1 and 2 can use DMA
+ */
+#define STM_NUM_SPI    2
+
+struct stm_spi {
+       vuint32_t       cr1;
+       vuint32_t       cr2;
+       vuint32_t       sr;
+       vuint32_t       dr;
+       vuint32_t       crcpr;
+       vuint32_t       rxcrcr;
+       vuint32_t       txcrcr;
+};
+
+extern struct stm_spi stm_spi1, stm_spi2, stm_spi3;
+
+/* SPI channels go from 1 to 3, instead of 0 to 2 (sigh)
+ */
+
+#define STM_SPI_INDEX(channel)         ((channel) - 1)
+
+#define STM_SPI_CR1_BIDIMODE           15
+#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_RXONLY             10
+#define STM_SPI_CR1_SSM                        9
+#define STM_SPI_CR1_SSI                        8
+#define STM_SPI_CR1_LSBFIRST           7
+#define STM_SPI_CR1_SPE                        6
+#define STM_SPI_CR1_BR                 3
+#define  STM_SPI_CR1_BR_PCLK_2                 0
+#define  STM_SPI_CR1_BR_PCLK_4                 1
+#define  STM_SPI_CR1_BR_PCLK_8                 2
+#define  STM_SPI_CR1_BR_PCLK_16                        3
+#define  STM_SPI_CR1_BR_PCLK_32                        4
+#define  STM_SPI_CR1_BR_PCLK_64                        5
+#define  STM_SPI_CR1_BR_PCLK_128               6
+#define  STM_SPI_CR1_BR_PCLK_256               7
+#define  STM_SPI_CR1_BR_MASK                   7
+
+#define STM_SPI_CR1_MSTR               2
+#define STM_SPI_CR1_CPOL               1
+#define STM_SPI_CR1_CPHA               0
+
+#define STM_SPI_CR2_TXEIE      7
+#define STM_SPI_CR2_RXNEIE     6
+#define STM_SPI_CR2_ERRIE      5
+#define STM_SPI_CR2_SSOE       2
+#define STM_SPI_CR2_TXDMAEN    1
+#define STM_SPI_CR2_RXDMAEN    0
+
+#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_TXE         1
+#define STM_SPI_SR_RXNE                0
+
 #endif /* _STM32L_H_ */