#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
#include <ao_arch_funcs.h>
+/*
+ * ao_ms5607.c
+ */
+
+void ao_ms5607_init(void);
+
#endif /* _AO_H_ */
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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_ */
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
ao_cmd_init();
ao_gps_init();
ao_config_init();
+ ao_dma_init();
+ ao_spi_init();
+ ao_ms5607_init();
ao_start_scheduler();
return 0;
#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
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
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)
{
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;
}
#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
#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]); }
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_ */
--- /dev/null
+/*
+ * 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);
+ }
+
+}
--- /dev/null
+/*
+ * 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
+}
}
}
+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;
#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 {
};
#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_ */