From: Keith Packard Date: Sun, 18 Dec 2022 01:36:00 +0000 (-0800) Subject: altos: Start work on LPC I2C driver X-Git-Url: https://git.gag.com/?a=commitdiff_plain;h=bd5360f5eac2cfd34c20460e3203c277abee75ce;p=fw%2Faltos altos: Start work on LPC I2C driver The motor test stand will need this Signed-off-by: Keith Packard --- diff --git a/src/lpc/ao_arch_funcs.h b/src/lpc/ao_arch_funcs.h index e88b0141..09cd0c03 100644 --- a/src/lpc/ao_arch_funcs.h +++ b/src/lpc/ao_arch_funcs.h @@ -183,6 +183,12 @@ static inline void ao_arch_restore_stack(void) { ao_arch_irqrestore(__mask); \ } while (0) +/* + * I2C + */ + +#include + /* * SPI */ diff --git a/src/lpc/ao_i2c_lpc.c b/src/lpc/ao_i2c_lpc.c new file mode 100644 index 00000000..21eb22db --- /dev/null +++ b/src/lpc/ao_i2c_lpc.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2021 Keith Packard + * + * 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 + +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); +} diff --git a/src/lpc/lpc.h b/src/lpc/lpc.h index be0dc021..218720e2 100644 --- a/src/lpc/lpc.h +++ b/src/lpc/lpc.h @@ -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 */ diff --git a/src/lpc/registers.ld b/src/lpc/registers.ld index 61dd9e70..c6f1c66c 100644 --- a/src/lpc/registers.ld +++ b/src/lpc/registers.ld @@ -1,5 +1,6 @@ lpc_usb_sram = 0x20004000; lpc_usb_endpoint = 0x20004700; +lpc_i2c = 0x40000000; lpc_usart = 0x40008000; lpc_ct16b0 = 0x4000c000; lpc_ct16b1 = 0x40010000; diff --git a/src/lpcxpresso/Makefile b/src/lpcxpresso/Makefile index d11d4205..d46bdccc 100644 --- a/src/lpcxpresso/Makefile +++ b/src/lpcxpresso/Makefile @@ -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: diff --git a/src/lpcxpresso/ao_demo.c b/src/lpcxpresso/ao_demo.c index a6b2242b..4af184c6 100644 --- a/src/lpcxpresso/ao_demo.c +++ b/src/lpcxpresso/ao_demo.c @@ -19,6 +19,21 @@ #include #include #include +#include + +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(); } diff --git a/src/lpcxpresso/ao_pins.h b/src/lpcxpresso/ao_pins.h index 2658d8f9..889465cb 100644 --- a/src/lpcxpresso/ao_pins.h +++ b/src/lpcxpresso/ao_pins.h @@ -16,6 +16,10 @@ * 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 diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 9922513b..589e8573 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -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 #if USE_SERIAL_1_SW_FLOW || USE_SERIAL_2_SW_FLOW || USE_SERIAL_3_SW_FLOW #define HAS_SERIAL_SW_FLOW 1