chaoskey-v1.0 chaoskey-v1.0/flash-loader \
telemini-v3.0 telemini-v3.0/flash-loader \
easymini-v2.0 easymini-v2.0/flash-loader \
+ snekboard snekboard/flash-loader \
micropeak-v2.0
AVRDIRS=\
ao_enable_output(port, pin, 1);
}
+/* ao_spi_samd21.c */
+
+#define AO_SPI_CPOL_BIT 6
+#define AO_SPI_CPHA_BIT 7
+
+#define AO_SPI_CONFIG_1 0x00
+/*
+ * PA08 SERCOM0.0 -> MOSI (DOPO 0)
+ * PA09 SERCOM0.1 -> SCLK (DOPO 0)
+ * PA10 SERCOM0.2 -> MISO (DIPO 2)
+ */
+#define AO_SPI_0_CONFIG_PA08_PA09_PA10 AO_SPI_CONFIG_1
+
+#define AO_SPI_CONFIG_2 0x08
+/*
+ * PA04 SERCOM0.0 -> MOSI (DOPO 0)
+ * PA05 SERCOM0.1 -> SCLK (DOPO 0)
+ * PA16 SERCOM0.2 -> MISO (DIPO 2)
+ */
+#define AO_SPI_0_CONFIG_PA04_PA05_PA06 AO_SPI_CONFIG_2
+
+#define AO_SPI_CONFIG_NONE 0x0c
+
+#define AO_SPI_INDEX_MASK 0x07
+#define AO_SPI_CONFIG_MASK 0x18
+
+#define AO_SPI_INDEX(id) ((id) & AO_SPI_INDEX_MASK)
+#define AO_SPI_CONFIG(id) ((id) & AO_SPI_CONFIG_MASK)
+#define AO_SPI_PIN_CONFIG(id) ((id) & (AO_SPI_INDEX_MASK | AO_SPI_CONFIG_MASK))
+#define AO_SPI_CPOL(id) ((uint32_t) (((id) >> AO_SPI_CPOL_BIT) & 1))
+#define AO_SPI_CPHA(id) ((uint32_t) (((id) >> AO_SPI_CPHA_BIT) & 1))
+
+/*
+ * We're not going to do any fancy SPI pin remapping, just use the first
+ * three PAD pins, which means:
+ *
+ * MOSI: PAD.0
+ * SCK: PAD.1
+ * MISO: PAD.2
+ */
+
+#define AO_SPI_0_PA08_PA09_PA10 (0 | AO_SPI_0_CONFIG_PA08_PA09_PA10)
+#define AO_SPI_0_PA04_PA05_PA06 (0 | AO_SPI_0_CONFIG_PA04_PA05_PA06)
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index);
+
+void
+ao_spi_get(uint8_t spi_index, uint32_t speed);
+
+void
+ao_spi_put(uint8_t spi_index);
+
+void
+ao_spi_init(void);
+
+#define ao_spi_get_mask(reg,mask,bus, speed) do { \
+ ao_spi_get(bus, speed); \
+ ao_spi_set_cs(reg,mask); \
+ } while (0)
+
+#define ao_spi_put_mask(reg,mask,bus) do { \
+ ao_spi_clr_cs(reg,mask); \
+ ao_spi_put(bus); \
+ } while (0)
+
+static inline void
+ao_spi_get_bit(struct samd21_port *port, uint8_t bit, uint8_t bus, uint32_t speed)
+{
+ ao_spi_get(bus, speed);
+ ao_gpio_set(port, bit, 0);
+}
+
+static inline void
+ao_spi_put_bit(struct samd21_port *port, uint8_t bit, uint8_t bus)
+{
+ ao_gpio_set(port, bit, 1);
+ ao_spi_put(bus);
+}
+
+static inline uint8_t
+ao_spi_speed(uint32_t hz)
+{
+ int32_t baud = (int32_t) (AO_SYSCLK / (2 * hz)) - 1;
+
+ if (baud < 0)
+ baud = 0;
+ if (baud > 255)
+ baud = 255;
+ return (uint8_t) baud;
+}
+
+#define ao_spi_init_cs(port, mask) do { \
+ uint8_t __bit__; \
+ for (__bit__ = 0; __bit__ < 32; __bit__++) { \
+ if (mask & (1 << __bit__)) \
+ ao_enable_output(port, __bit__, 1); \
+ } \
+ } while (0)
+
#define ARM_PUSH32(stack, val) (*(--(stack)) = (val))
typedef uint32_t ao_arch_irq_t;
--- /dev/null
+/*
+ * Copyright © 2022 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, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * 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.
+ */
+
+#include <ao.h>
+
+static uint8_t ao_spi_mutex[SAMD21_NUM_SERCOM];
+static uint8_t ao_spi_pin_config[SAMD21_NUM_SERCOM];
+
+struct ao_spi_samd21_info {
+ struct samd21_sercom *sercom;
+};
+
+static const struct ao_spi_samd21_info ao_spi_samd21_info[SAMD21_NUM_SERCOM] = {
+ {
+ .sercom = &samd21_sercom0,
+ },
+ {
+ .sercom = &samd21_sercom1,
+ },
+ {
+ .sercom = &samd21_sercom2,
+ },
+ {
+ .sercom = &samd21_sercom3,
+ },
+ {
+ .sercom = &samd21_sercom4,
+ },
+ {
+ .sercom = &samd21_sercom5,
+ },
+};
+
+//static uint8_t spi_dev_null;
+
+void
+ao_spi_send(const void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ const uint8_t *b = block;
+
+ while (len--) {
+ sercom->data = *b++;
+ while ((sercom->intflag & (1 << SAMD21_SERCOM_INTFLAG_RXC)) == 0)
+ ;
+ (void) sercom->data;
+ }
+}
+
+void
+ao_spi_recv(void *block, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ uint8_t *b = block;
+
+ while (len--) {
+ sercom->data = 0xff;
+ while ((sercom->intflag & (1 << SAMD21_SERCOM_INTFLAG_RXC)) == 0)
+ ;
+ *b++ = (uint8_t) sercom->data;
+ }
+}
+
+
+void
+ao_spi_duplex(const void *out, void *in, uint16_t len, uint8_t spi_index)
+{
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ const uint8_t *o = out;
+ uint8_t *i = in;
+
+ while (len--) {
+ sercom->data = *o++;
+ while ((sercom->intflag & (1 << SAMD21_SERCOM_INTFLAG_RXC)) == 0)
+ ;
+ *i++ = (uint8_t) sercom->data;
+ }
+}
+
+static void
+ao_spi_disable_pin_config(uint8_t spi_pin_config)
+{
+ switch (spi_pin_config) {
+#if HAS_SPI_0
+ case AO_SPI_0_PA08_PA09_PA10:
+ samd21_port_pmux_clr(&samd21_port_a, 8); /* MOSI */
+ samd21_port_pmux_clr(&samd21_port_a, 9); /* SCLK */
+ samd21_port_pmux_clr(&samd21_port_a, 10); /* MISO */
+ break;
+ case AO_SPI_0_PA04_PA05_PA06:
+ samd21_port_pmux_clr(&samd21_port_a, 4); /* MOSI */
+ samd21_port_pmux_clr(&samd21_port_a, 5); /* SCLK */
+ samd21_port_pmux_clr(&samd21_port_a, 6); /* MISO */
+ break;
+#endif
+ }
+}
+
+static void
+ao_spi_enable_pin_config(uint8_t spi_pin_config)
+{
+ switch (spi_pin_config) {
+#if HAS_SPI_0
+ case AO_SPI_0_PA08_PA09_PA10:
+ ao_enable_output(&samd21_port_a, 8, 1);
+ ao_enable_output(&samd21_port_a, 9, 1);
+ ao_enable_input(&samd21_port_a, 10, AO_MODE_PULL_NONE);
+ samd21_port_pmux_set(&samd21_port_a, 8, SAMD21_PORT_PMUX_FUNC_C); /* MOSI */
+ samd21_port_pmux_set(&samd21_port_a, 9, SAMD21_PORT_PMUX_FUNC_C); /* SCLK */
+ samd21_port_pmux_set(&samd21_port_a, 10, SAMD21_PORT_PMUX_FUNC_C); /* MISO */
+ break;
+ case AO_SPI_0_PA04_PA05_PA06:
+ ao_enable_output(&samd21_port_a, 4, 1);
+ ao_enable_output(&samd21_port_a, 5, 1);
+ ao_enable_input(&samd21_port_a, 6, AO_MODE_PULL_NONE);
+ samd21_port_pmux_set(&samd21_port_a, 4, SAMD21_PORT_PMUX_FUNC_C); /* MOSI */
+ samd21_port_pmux_set(&samd21_port_a, 5, SAMD21_PORT_PMUX_FUNC_C); /* SCLK */
+ samd21_port_pmux_set(&samd21_port_a, 6, SAMD21_PORT_PMUX_FUNC_C); /* MISO */
+ break;
+#endif
+ }
+}
+
+static void
+ao_spi_config(uint8_t spi_index, uint32_t baud)
+{
+ uint8_t spi_pin_config = AO_SPI_PIN_CONFIG(spi_index);
+ uint8_t id = AO_SPI_INDEX(spi_index);
+ struct samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ if (spi_pin_config != ao_spi_pin_config[id]) {
+ ao_spi_disable_pin_config(ao_spi_pin_config[id]);
+ ao_spi_enable_pin_config(spi_pin_config);
+ ao_spi_pin_config[id] = spi_pin_config;
+ }
+
+ sercom->baud = (uint16_t) baud;
+
+ /* Set spi mode */
+ uint32_t ctrla = sercom->ctrla;
+ ctrla &= ~((1UL << SAMD21_SERCOM_CTRLA_CPOL) |
+ (1UL << SAMD21_SERCOM_CTRLA_CPHA));
+ ctrla |= ((AO_SPI_CPOL(spi_index) << SAMD21_SERCOM_CTRLA_CPOL) |
+ (AO_SPI_CPHA(spi_index) << SAMD21_SERCOM_CTRLA_CPHA));
+
+ /* finish setup and enable the hardware */
+ ctrla |= (1 << SAMD21_SERCOM_CTRLA_ENABLE);
+
+ sercom->ctrla = ctrla;
+
+ while (sercom->syncbusy & (1 << SAMD21_SERCOM_SYNCBUSY_ENABLE))
+ ;
+}
+
+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 samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ sercom->ctrla &= ~(1UL << SAMD21_SERCOM_CTRLA_ENABLE);
+ while (sercom->syncbusy & (1 << SAMD21_SERCOM_SYNCBUSY_ENABLE))
+ ;
+ ao_mutex_put(&ao_spi_mutex[id]);
+}
+
+static void
+ao_spi_init_sercom(uint8_t id)
+{
+ struct samd21_sercom *sercom = ao_spi_samd21_info[id].sercom;
+
+ /* Send a clock along */
+ samd21_gclk_clkctrl(0, SAMD21_GCLK_CLKCTRL_ID_SERCOM0_CORE + id);
+
+ samd21_nvic_set_enable(SAMD21_NVIC_ISR_SERCOM0_POS + id);
+ samd21_nvic_set_priority(SAMD21_NVIC_ISR_SERCOM0_POS + id, 4);
+
+ /* Enable */
+ samd21_pm.apbcmask |= (1 << (SAMD21_PM_APBCMASK_SERCOM0 + id));
+
+ /* Reset */
+ sercom->ctrla = (1 << SAMD21_SERCOM_CTRLA_SWRST);
+
+ while ((sercom->ctrla & (1 << SAMD21_SERCOM_CTRLA_SWRST)) ||
+ (sercom->syncbusy & (1 << SAMD21_SERCOM_SYNCBUSY_SWRST)))
+ ;
+
+ /* set SPI mode */
+ sercom->ctrla = ((SAMD21_SERCOM_CTRLA_DORD_MSB << SAMD21_SERCOM_CTRLA_DORD) |
+ (0 << SAMD21_SERCOM_CTRLA_CPOL) |
+ (0 << SAMD21_SERCOM_CTRLA_CPHA) |
+ (0 << SAMD21_SERCOM_CTRLA_FORM) |
+ (2 << SAMD21_SERCOM_CTRLA_DIPO) |
+ (0 << SAMD21_SERCOM_CTRLA_DOPO) |
+ (0 << SAMD21_SERCOM_CTRLA_IBON) |
+ (0 << SAMD21_SERCOM_CTRLA_RUNSTDBY) |
+ (SAMD21_SERCOM_CTRLA_MODE_SPI_HOST << SAMD21_SERCOM_CTRLA_MODE) |
+ (0 << SAMD21_SERCOM_CTRLA_ENABLE) |
+ (0 << SAMD21_SERCOM_CTRLA_SWRST));
+
+ sercom->ctrlb = ((1 << SAMD21_SERCOM_CTRLB_RXEN) |
+ (0 << SAMD21_SERCOM_CTRLB_AMODE) |
+ (0 << SAMD21_SERCOM_CTRLB_MSSEN) |
+ (0 << SAMD21_SERCOM_CTRLB_SSDE) |
+ (0 << SAMD21_SERCOM_CTRLB_PLOADEN) |
+ (SAMD21_SERCOM_CTRLB_CHSIZE_8 << SAMD21_SERCOM_CTRLB_CHSIZE));
+
+
+ ao_spi_enable_pin_config(id);
+}
+
+void
+ao_spi_init(void)
+{
+#if HAS_SPI_0
+ ao_spi_init_sercom(0);
+#endif
+#if HAS_SPI_1
+ ao_spi_init_sercom(1);
+#endif
+#if HAS_SPI_2
+ ao_spi_init_sercom(2);
+#endif
+#if HAS_SPI_3
+ ao_spi_init_sercom(3);
+#endif
+#if HAS_SPI_4
+ ao_spi_init_sercom(4);
+#endif
+#if HAS_SPI_5
+ ao_spi_init_sercom(5);
+#endif
+}
(1 << SAMD21_PORT_PINCFG_PMUXEN));
}
+static inline void
+samd21_port_pmux_clr(struct samd21_port *port, uint8_t pin)
+{
+ samd21_port_pincfg_set(port, pin,
+ (0 << SAMD21_PORT_PINCFG_PMUXEN),
+ (1 << SAMD21_PORT_PINCFG_PMUXEN));
+}
+
struct samd21_adc {
vuint8_t ctrla;
vuint8_t refctrl;
extern struct samd21_sercom samd21_sercom4;
extern struct samd21_sercom samd21_sercom5;
+#define SAMD21_NUM_SERCOM 6
+
#define samd21_sercom0 (*(struct samd21_sercom *) 0x42000800)
#define samd21_sercom1 (*(struct samd21_sercom *) 0x42000c00)
#define samd21_sercom2 (*(struct samd21_sercom *) 0x42001000)
#define SAMD21_SERCOM_CTRLA_ENABLE 1
#define SAMD21_SERCOM_CTRLA_MODE 2
# define SAMD21_SERCOM_CTRLA_MODE_USART 1
-# define SAMD21_SERCOM_CTRLA_MODE_I2C_LEADER 5
+# define SAMD21_SERCOM_CTRLA_MODE_SPI_CLIENT 2
+# define SAMD21_SERCOM_CTRLA_MODE_SPI_HOST 3
+# define SAMD21_SERCOM_CTRLA_MODE_I2C_CLIENT 4
+# define SAMD21_SERCOM_CTRLA_MODE_I2C_HOST 5
#define SAMD21_SERCOM_CTRLA_RUNSTDBY 7
#define SAMD21_SERCOM_CTRLA_INACTOUT_205US 3
#define SAMD21_SERCOM_CTRLA_LOWTOUT 30
+/* SPI controller mode */
+#define SAMD21_SERCOM_CTRLA_DOPO 16
+#define SAMD21_SERCOM_CTRLA_DIPO 20
+#define SAMD21_SERCOM_CTRLA_FORM 24
+#define SAMD21_SERCOM_CTRLA_CPHA 28
+#define SAMD21_SERCOM_CTRLA_CPOL 29
+#define SAMD21_SERCOM_CTRLA_DORD 30
+#define SAMD21_SERCOM_CTRLA_DORD_LSB 1
+#define SAMD21_SERCOM_CTRLA_DORD_MSB 0
+
/* USART mode */
#define SAMD21_SERCOM_CTRLB_CHSIZE 0
#define SAMD21_SERCOM_CTRLB_SBMODE 6
#define SAMD21_SERCOM_CTRLB_ACKACT_NACK 1
#define SAMD21_SERCOM_CTRLB_FIFOCLR 22
+/* SPI mode */
+#define SAMD21_SERCOM_CTRLB_CHSIZE 0
+# define SAMD21_SERCOM_CTRLB_CHSIZE_8 0
+#define SAMD21_SERCOM_CTRLB_PLOADEN 6
+#define SAMD21_SERCOM_CTRLB_SSDE 9
+#define SAMD21_SERCOM_CTRLB_MSSEN 13
+#define SAMD21_SERCOM_CTRLB_AMODE 14
+#define SAMD21_SERCOM_CTRLB_RXEN 17
+
/* USART mode */
#define SAMD21_SERCOM_INTFLAG_DRE 0
#define SAMD21_SERCOM_INTFLAG_TXC 1
#define SAMD21_SERCOM_INTFLAG_SB 1
#define SAMD21_SERCOM_INTFLAG_MB 0
+/* SPI mode */
+#define SAMD21_SERCOM_INTFLAG_SSL 3
+
#define SAMD21_SERCOM_INTENCLR_DRE 0
#define SAMD21_SERCOM_INTENCLR_TXC 1
#define SAMD21_SERCOM_INTENCLR_RXC 2
#define SAMD21_SERCOM_STATUS_PERR 0
#define SAMD21_SERCOM_STATUS_FERR 1
#define SAMD21_SERCOM_STATUS_BUFOVF 2
-#define SAMD21_SERCOM_STATUS_CTS 3
-#define SAMD21_SERCOM_STATUS_ISF 4
+#define SAMD21_SERCOM_STATUS_CTS 3
+#define SAMD21_SERCOM_STATUS_ISF 4
#define SAMD21_SERCOM_STATUS_COLL 5
-#define SAMD21_SERCOM_STATUS_TXE 6
+#define SAMD21_SERCOM_STATUS_TXE 6
#define SAMD21_SERCOM_SYNCBUSY_SWRST 0
#define SAMD21_SERCOM_SYNCBUSY_ENABLE 1
#define AO_AHB_PRESCALER 1
#define AO_APBA_PRESCALER 1
+#define HAS_SPI_0 1
+#define SPI_0_PA08_PA09_PA10_PA11 1
+
#endif /* _AO_PINS_H_ */
#define AO_RN_SW_BTN_PORT (&stm_gpioc)
#define AO_RN_SW_BTN_PIN 14
-/* Pin 9. BM70 P2_3 */
-#define AO_RN_WAKEUP_PORT (&stm_gpiob)
-#define AO_RN_WAKEUP_PIN 9
-
-/* Pin 11. BM70 P2_7/tx_ind. Status indication along with P1_5 */
-#define AO_RN_P0_4_PORT (&stm_gpioc)
-#define AO_RN_P0_4_PIN 13
-
-/* Pin 12. BM70 P1_1. Status indication along with P0_4 */
+/* Pin 12. BM70 P1_5. Status indication along with P0_4 */
#define AO_RN_P1_5_PORT (&stm_gpiob)
#define AO_RN_P1_5_PIN 6
-/* Pin 13. BM70 P1_2. Also I2C SCL */
-#define AO_RN_P1_2_PORT (&stm_gpiob)
-#define AO_RN_P1_2_PIN 7
-
-/* Pin 14. BM70 P1_3. Also I2C SDA */
-#define AO_RN_P1_3_PORT (&stm_gpiob)
-#define AO_RN_P1_3_PIN 8
-
-/* Pin 15. BM70 P0_0/cts. */
-#define AO_RN_CTS_PORT (&stm_gpioa)
-#define AO_RN_CTS_PIN 1
-
-/* Pin 16. BM70 P1_0. */
-#define AO_RN_P0_5_PORT (&stm_gpiob)
-#define AO_RN_P0_5_PIN 5
-
-/* Pin 17. BM70 P3_6. */
-#define AO_RN_RTS_PORT (&stm_gpioa)
-#define AO_RN_RTS_PIN 0
-
-/* Pin 18. BM70 P2_0. */
-#define AO_RN_P2_0_PORT (&stm_gpiob)
-#define AO_RN_P2_0_PIN 3
-
-/* Pin 19. BM70 P2_4. */
-#define AO_RN_P2_4_PORT (&stm_gpioa)
-#define AO_RN_P2_4_PIN 10
-
-/* Pin 20. BM70 NC. */
-#define AO_RN_EAN_PORT
-#define AO_RN_EAN_PIN
-
/* Pin 21. BM70 RST_N. */
#define AO_RN_RST_N_PORT (&stm_gpioa)
#define AO_RN_RST_N_PIN 15
#define AO_RN_P3_1_PORT (&stm_gpiob)
#define AO_RN_P3_1_PIN 2
-/* Pin 25. BM70 P3_2/LINK_DROP. */
-#define AO_RN_P3_2_PORT (&stm_gpioa)
-#define AO_RN_P3_2_PIN 8
-
-/* Pin 26. BM70 P3_3/UART_RX_IND. */
-#define AO_RN_P3_3_PORT (&stm_gpiob)
-#define AO_RN_P3_3_PIN 15
-
-/* Pin 27. BM70 P3_4/PAIRING_KEY. */
-#define AO_RN_P3_4_PORT (&stm_gpiob)
-#define AO_RN_P3_4_PIN 14
-
-/* Pin 28. BM70 P3_5. */
-#define AO_RN_P3_6_PORT (&stm_gpiob)
-#define AO_RN_P3_6_PIN 13
-
/* Pin 29. BM70 P0_7. */
#define AO_RN_P3_7_PORT (&stm_gpiob)
#define AO_RN_P3_7_PIN 12