altos: Start work on LPC I2C driver
authorKeith Packard <keithp@keithp.com>
Sun, 18 Dec 2022 01:36:00 +0000 (17:36 -0800)
committerKeith Packard <keithp@keithp.com>
Mon, 19 Dec 2022 20:45:33 +0000 (12:45 -0800)
The motor test stand will need this

Signed-off-by: Keith Packard <keithp@keithp.com>
src/lpc/ao_arch_funcs.h
src/lpc/ao_i2c_lpc.c [new file with mode: 0644]
src/lpc/lpc.h
src/lpc/registers.ld
src/lpcxpresso/Makefile
src/lpcxpresso/ao_demo.c
src/lpcxpresso/ao_pins.h
src/stm/ao_arch_funcs.h

index e88b0141f9ad7c37ea8785e448d9a59411b142f7..09cd0c03ed489dc59340ca6a0b62cb2a3f700358 100644 (file)
@@ -183,6 +183,12 @@ static inline void ao_arch_restore_stack(void) {
                ao_arch_irqrestore(__mask);             \
        } while (0)
 
+/*
+ * I2C
+ */
+
+#include <ao_i2c.h>
+
 /*
  * SPI
  */
diff --git a/src/lpc/ao_i2c_lpc.c b/src/lpc/ao_i2c_lpc.c
new file mode 100644 (file)
index 0000000..21eb22d
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * Copyright © 2021 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.
+ *
+ * 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>
+
+static uint8_t ao_i2c_mutex;
+
+static const uint8_t   *i2c_send;
+static uint16_t                i2c_send_len;
+static uint8_t         *i2c_recv;
+static uint16_t                i2c_recv_len;
+static uint8_t         i2c_stop;
+static uint8_t         i2c_error;
+
+static void
+_ao_i2c_put_byte(void)
+{
+       lpc_i2c.dat = *i2c_send++;
+       lpc_i2c.conset = (1 << LPC_I2C_CONSET_AA);
+}
+
+static void
+_ao_i2c_get_byte(void)
+{
+       *i2c_recv++ = (uint8_t) lpc_i2c.dat;
+       i2c_recv_len--;
+       if (i2c_recv_len == 0) {
+               lpc_i2c.conclr = (1 << LPC_I2C_CONCLR_AAC);
+               ao_wakeup(&i2c_recv_len);
+       } else {
+               lpc_i2c.conset = (1 << LPC_I2C_CONSET_AA);
+       }
+}
+
+void
+lpc_i2c_isr(void)
+{
+       switch (lpc_i2c.stat) {
+       case LPC_I2C_STAT_ERROR:
+               lpc_i2c.conset = ((1 << LPC_I2C_CONSET_STO) |
+                                 (1 << LPC_I2C_CONSET_AA));
+               break;
+       case LPC_I2C_STAT_START:
+       case LPC_I2C_STAT_REPEAT_START:
+               i2c_error = 0;
+               /* fall through ... */
+       case LPC_I2C_STAT_TX_START_ACK:
+       case LPC_I2C_STAT_TX_ACK:
+               --i2c_send_len;
+               if (i2c_send_len) {
+                       _ao_i2c_put_byte();
+               } else {
+                       if (i2c_stop)
+                               lpc_i2c.conset =(1 << LPC_I2C_CONSET_STO);
+                       ao_wakeup(&i2c_send_len);
+               }
+               break;
+       case LPC_I2C_STAT_TX_START_NACK:
+       case LPC_I2C_STAT_TX_NACK:
+               lpc_i2c.conset = ((1 << LPC_I2C_CONSET_AA) |
+                                 (1 << LPC_I2C_CONSET_STO));
+               i2c_send_len = 0;
+               i2c_error = 1;
+               ao_wakeup(&i2c_send_len);
+               break;
+       case LPC_I2C_STAT_TX_ARB_LOST:
+               lpc_i2c.conset =((1 << LPC_I2C_CONSET_AA)|
+                                (1 << LPC_I2C_CONSET_STA));
+               break;
+       case LPC_I2C_STAT_RX_START_ACK:
+               lpc_i2c.conset = (1 << LPC_I2C_CONSET_AA);
+               break;
+       case LPC_I2C_STAT_RX_START_NACK:
+       case LPC_I2C_STAT_RX_NACK:
+               lpc_i2c.conset = ((1 << LPC_I2C_CONSET_AA) |
+                                 (1 << LPC_I2C_CONSET_STO));
+               i2c_recv_len = 0;
+               i2c_error = 1;
+               ao_wakeup(&i2c_recv_len);
+               break;
+       case LPC_I2C_STAT_RX_ACK:
+               if (i2c_recv_len)
+                       _ao_i2c_get_byte();
+               break;
+       }
+       lpc_i2c.conclr = (1 << LPC_I2C_CONCLR_SIC);
+}
+
+void
+ao_i2c_get(uint8_t index)
+{
+       (void) index;
+       ao_mutex_get(&ao_i2c_mutex);
+       lpc_i2c.conset = (1 << LPC_I2C_CONSET_I2EN);
+}
+
+void
+ao_i2c_put(uint8_t index)
+{
+       (void) index;
+       lpc_i2c.conclr = (1 << LPC_I2C_CONCLR_I2ENC);
+       ao_mutex_put(&ao_i2c_mutex);
+}
+
+uint8_t
+ao_i2c_start(uint8_t index, uint16_t addr)
+{
+       uint8_t a = (uint8_t) addr;
+
+       (void) index;
+       ao_arch_block_interrupts();
+       i2c_send = &a;
+       i2c_send_len = 1;
+       i2c_stop = 0;
+       lpc_i2c.conset = (1 << LPC_I2C_CONSET_STA);
+       while (i2c_send_len)
+               ao_sleep(&i2c_send_len);
+       ao_arch_release_interrupts();
+       return 0;
+}
+
+uint8_t
+ao_i2c_send(const void *block, uint16_t len, uint8_t index, uint8_t stop)
+{
+       (void) index;
+       ao_arch_block_interrupts();
+       i2c_send = block;
+       i2c_send_len = len;
+       i2c_stop = stop;
+       _ao_i2c_put_byte();
+       while (i2c_send_len)
+               ao_sleep(&i2c_send_len);
+       ao_arch_release_interrupts();
+       return 0;
+}
+
+uint8_t
+ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop)
+{
+       (void) index;
+       ao_arch_block_interrupts();
+       i2c_recv = block;
+       i2c_recv_len = len;
+       i2c_stop = stop;
+       /* Check to see if a byte is already here */
+       if (lpc_i2c.stat == LPC_I2C_STAT_RX_ACK)
+               _ao_i2c_get_byte();
+       while (i2c_recv_len)
+               ao_sleep(&i2c_recv_len);
+       ao_arch_release_interrupts();
+       return 0;
+}
+
+void
+ao_i2c_init(void)
+{
+       /* Configure pins */
+       lpc_ioconf.pio0_4 = ao_lpc_alternate(LPC_IOCONF_FUNC_I2C_SCL);
+       lpc_ioconf.pio0_5 = ao_lpc_alternate(LPC_IOCONF_FUNC_I2C_SDA);
+
+       /* Enable the device */
+       lpc_scb.sysahbclkctrl |= (1 << LPC_SCB_SYSAHBCLKCTRL_I2C);
+
+       /* Reset the device */
+       lpc_scb.presetctrl &= ~(1UL << LPC_SCB_PRESETCTRL_I2C_RST_N);
+       lpc_scb.presetctrl |= (1 << LPC_SCB_PRESETCTRL_I2C_RST_N);
+}
index be0dc021d7a7cf6e12629349b8398d0543161ef4..218720e2f1e4f12070a3c41dbf49d725957bc276 100644 (file)
@@ -640,6 +640,62 @@ extern struct lpc_scb lpc_scb;
 #define LPC_SCB_PDRUNCFG_USBPLL_PD     8
 #define LPC_SCB_PDRUNCFG_USBPAD_PD     10
 
+struct lpc_i2c {
+       vuint32_t       conset;
+       vuint32_t       stat;
+       vuint32_t       dat;
+       vuint32_t       adr0;
+
+       vuint32_t       sclh;
+       vuint32_t       scll;
+       vuint32_t       conclr;
+       vuint32_t       mmctrl;
+
+       vuint32_t       adr[3];
+       vuint32_t       data_buffer;
+
+       vuint32_t       mask[4];
+};
+
+extern struct lpc_i2c lpc_i2c;
+
+#define lpc_i2c (*(struct lpc_i2c *) 0x40000000)
+
+#define LPC_I2C_CONSET_AA      2
+#define LPC_I2C_CONSET_SI      3
+#define LPC_I2C_CONSET_STO     4
+#define LPC_I2C_CONSET_STA     5
+#define LPC_I2C_CONSET_I2EN    6
+
+/* master status values */
+#define LPC_I2C_STAT_ERROR             0x00
+#define LPC_I2C_STAT_START             0x08
+#define LPC_I2C_STAT_REPEAT_START      0x10
+#define LPC_I2C_STAT_TX_START_ACK      0x18
+#define LPC_I2C_STAT_TX_START_NACK     0x20
+#define LPC_I2C_STAT_TX_ACK            0x28
+#define LPC_I2C_STAT_TX_NACK           0x30
+#define LPC_I2C_STAT_TX_ARB_LOST       0x38
+#define LPC_I2C_STAT_RX_START_ACK      0x40
+#define LPC_I2C_STAT_RX_START_NACK     0x48
+#define LPC_I2C_STAT_RX_ACK            0x50
+#define LPC_I2C_STAT_RX_NACK           0x58
+
+
+#define LPC_I2C_ADR_GC         0
+#define LPC_I2C_ADR_ADDRESS    1
+
+#define LPC_I2C_CONCLR_AAC     2
+#define LPC_I2C_CONCLR_SIC     3
+#define LPC_I2C_CONCLR_STAC    5
+#define LPC_I2C_CONCLR_I2ENC   6
+
+#define LPC_I2C_MMCTRL_MM_ENA  0
+#define LPC_I2C_MMCTRL_ENA_SCL 1
+#define LPC_I2C_MMCTRL_MATCH_ALL       2
+
+#define LPC_I2C_MASK_MASK      1
+
 struct lpc_flash {
        uint32_t        r0[4];          /* 0x0 */
 
index 61dd9e7076c0dca5130badee0868fcd2a3e4fe1e..c6f1c66c4b473ec882ef278762cb8c9e934ece0f 100644 (file)
@@ -1,5 +1,6 @@
 lpc_usb_sram   = 0x20004000;
 lpc_usb_endpoint = 0x20004700;
+lpc_i2c                = 0x40000000;
 lpc_usart      = 0x40008000;
 lpc_ct16b0     = 0x4000c000;
 lpc_ct16b1     = 0x40010000;
index d11d420592dcb2f82515d21f70a71264fddaad10..d46bdccc99b935106dff56591ac8c80d2effd0a7 100644 (file)
@@ -22,11 +22,13 @@ ALTOS_SRC = \
        ao_romconfig.c \
        ao_product.c \
        ao_panic.c \
+       ao_mutex.c \
        ao_led_lpc.c \
        ao_task.c \
        ao_cmd.c \
        ao_timer_lpc.c \
        ao_serial_lpc.c \
+       ao_i2c_lpc.c \
        ao_usb_lpc.c \
        ao_exti_lpc.c \
        ao_stdio.c
@@ -46,7 +48,7 @@ BOTH_HEX=$(PROGNAME)-combined-$(VERSION).ihx
 SRC=$(ALTOS_SRC) ao_demo.c
 OBJ=$(SRC:.c=.o)
 
-all: $(PROG)
+all: $(PROG) $(HEX)
 
 $(PROG): Makefile $(OBJ) altos.ld
        $(call quiet,CC) $(LDFLAGS) -o $(PROG) $(OBJ) $(LIBS)
@@ -65,3 +67,5 @@ clean:
 install:
 
 uninstall:
+
+FRC:
index a6b2242ba7620eb8e609baaf5b999f8d34f36077..4af184c6d129f86ca2f5c5b2c3e45c39d8313383 100644 (file)
 #include <ao.h>
 #include <ao_exti.h>
 #include <ao_i2c.h>
+#include <ao_i2c.h>
+
+static void
+ao_i2c_test(void)
+{
+       ao_i2c_get(0);
+       ao_i2c_start(0, 0x44);
+       ao_i2c_send("hello", 5, 0, 1);
+       ao_i2c_put(0);
+}
+
+const struct ao_cmds ao_test_cmds[] = {
+       { ao_i2c_test,  "s \0Send some bytes over i2c" },
+       { 0, NULL },
+};
 
 int
 main(void)
@@ -35,6 +50,6 @@ main(void)
        ao_serial_init();
        ao_i2c_init();
        ao_cmd_init();
-
+       ao_cmd_register(ao_test_cmds);
        ao_start_scheduler();
 }
index 2658d8f9e0487a65cd0b6249849faabd93bc9c4b..889465cb0c097ac5d21c5f632eabdecd694328ad 100644 (file)
  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
  */
 
+#define IS_FLASH_LOADER        0
+
+#define HAS_LED                1
+
 #define HAS_BEEP       0
 
 #define IS_FLASH_LOADER        0
index 9922513be007bf005c19c9d9d1cd5021e3266300..589e85732f65b1da5a16037a7970f1c2740a4ddc 100644 (file)
@@ -351,23 +351,7 @@ ao_dma_init(void);
 
 /* ao_i2c_stm.c */
 
-void
-ao_i2c_get(uint8_t i2c_index);
-
-uint8_t
-ao_i2c_start(uint8_t i2c_index, uint16_t address);
-
-void
-ao_i2c_put(uint8_t i2c_index);
-
-uint8_t
-ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
-
-uint8_t
-ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop);
-
-void
-ao_i2c_init(void);
+#include <ao_i2c.h>
 
 #if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW
 #define HAS_SERIAL_SW_FLOW 1