From: Keith Packard Date: Mon, 7 May 2012 05:47:33 +0000 (-0700) Subject: altos: STM i2c work. X-Git-Tag: 1.0.9.5~25^2~10 X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=commitdiff_plain;h=0f0cc91ce8e9807dca48a5c0c53d821f5060e245 altos: STM i2c work. Start now driven by interrupts Send now done with DMA and interrupts Signed-off-by: Keith Packard --- diff --git a/src/drivers/ao_hmc5883.c b/src/drivers/ao_hmc5883.c index 0077daf9..43d04f70 100644 --- a/src/drivers/ao_hmc5883.c +++ b/src/drivers/ao_hmc5883.c @@ -48,13 +48,10 @@ ao_hmc5883_write(uint8_t addr, uint8_t *data, uint8_t len) { ao_i2c_get(AO_HMC5883_I2C_INDEX); ao_i2c_start(AO_HMC5883_I2C_INDEX, HMC5883_ADDR_WRITE); - ao_i2c_send(&addr, 1, AO_HMC5883_I2C_INDEX); + ao_i2c_send(&addr, 1, AO_HMC5883_I2C_INDEX, FALSE); ao_hmc5883_addr_reg = addr; - if (len) { - ao_i2c_send(data, len, AO_HMC5883_I2C_INDEX); - ao_hmc5883_update_addr(len); - } - ao_i2c_stop(AO_HMC5883_I2C_INDEX); + ao_i2c_send(data, len, AO_HMC5883_I2C_INDEX, TRUE); + ao_hmc5883_update_addr(len); ao_i2c_put(AO_HMC5883_I2C_INDEX); } @@ -64,15 +61,12 @@ ao_hmc5883_read(uint8_t addr, uint8_t *data, uint8_t len) ao_i2c_get(AO_HMC5883_I2C_INDEX); if (addr != ao_hmc5883_addr_reg) { ao_i2c_start(AO_HMC5883_I2C_INDEX, HMC5883_ADDR_WRITE); - ao_i2c_send(&addr, 1, AO_HMC5883_I2C_INDEX); + ao_i2c_send(&addr, 1, AO_HMC5883_I2C_INDEX, FALSE); ao_hmc5883_addr_reg = addr; } ao_i2c_start(AO_HMC5883_I2C_INDEX, HMC5883_ADDR_READ); - if (len) { - ao_i2c_recv(data, len, AO_HMC5883_I2C_INDEX); - ao_hmc5883_update_addr(len); - } - ao_i2c_stop(AO_HMC5883_I2C_INDEX); + ao_i2c_recv(data, len, AO_HMC5883_I2C_INDEX, TRUE); + ao_hmc5883_update_addr(len); ao_i2c_put(AO_HMC5883_I2C_INDEX); } @@ -92,7 +86,7 @@ ao_hmc5883_setup(void) ao_i2c_get(AO_HMC5883_I2C_INDEX); present = ao_i2c_start(AO_HMC5883_I2C_INDEX, HMC5883_ADDR_READ); - ao_i2c_stop(AO_HMC5883_I2C_INDEX); + ao_i2c_recv(NULL, 0, AO_HMC5883_I2C_INDEX, TRUE); ao_i2c_put(AO_HMC5883_I2C_INDEX); if (!present) return 0; @@ -109,7 +103,7 @@ ao_hmc5883_show(void) { ao_i2c_get(AO_HMC5883_I2C_INDEX); data = ao_i2c_start(AO_HMC5883_I2C_INDEX, addr << 1); - ao_i2c_stop(AO_HMC5883_I2C_INDEX); + ao_i2c_recv(NULL, 0, AO_HMC5883_I2C_INDEX, TRUE); ao_i2c_put(AO_HMC5883_I2C_INDEX); if (data) printf("address %02x responds\n", addr << 1); diff --git a/src/drivers/ao_mpu6000.c b/src/drivers/ao_mpu6000.c index 290f1390..d7f67d6e 100644 --- a/src/drivers/ao_mpu6000.c +++ b/src/drivers/ao_mpu6000.c @@ -35,10 +35,8 @@ ao_mpu6000_write(uint8_t addr, uint8_t *data, uint8_t len) { ao_i2c_get(AO_MPU6000_I2C_INDEX); ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE); - ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX); - if (len) - ao_i2c_send(data, len, AO_MPU6000_I2C_INDEX); - ao_i2c_stop(AO_MPU6000_I2C_INDEX); + ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE); + ao_i2c_send(data, len, AO_MPU6000_I2C_INDEX, TRUE); ao_i2c_put(AO_MPU6000_I2C_INDEX); } @@ -47,11 +45,9 @@ ao_mpu6000_read(uint8_t addr, uint8_t *data, uint8_t len) { ao_i2c_get(AO_MPU6000_I2C_INDEX); ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_WRITE); - ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX); + ao_i2c_send(&addr, 1, AO_MPU6000_I2C_INDEX, FALSE); ao_i2c_start(AO_MPU6000_I2C_INDEX, MPU6000_ADDR_READ); - if (len) - ao_i2c_recv(data, len, AO_MPU6000_I2C_INDEX); - ao_i2c_stop(AO_MPU6000_I2C_INDEX); + ao_i2c_recv(data, len, AO_MPU6000_I2C_INDEX, TRUE); ao_i2c_put(AO_MPU6000_I2C_INDEX); } @@ -78,9 +74,11 @@ ao_mpu6000_show(void) ao_mpu6000_read(MPU6000_WHO_AM_I, data, 1); printf ("mpu6000 WHO_AM_I: %02x\n", data[0]); - ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, data, 1); +#if 0 + ao_mpu6000_read(MPU6000_ACCEL_XOUT_H, data, 14); for (i = 0; i < 14; i++) printf ("reg %02x: %02x\n", i + MPU6000_ACCEL_XOUT_H, data[i]); +#endif } static const struct ao_cmds ao_mpu6000_cmds[] = { diff --git a/src/stm/ao_arch_funcs.h b/src/stm/ao_arch_funcs.h index 3027b337..447042dd 100644 --- a/src/stm/ao_arch_funcs.h +++ b/src/stm/ao_arch_funcs.h @@ -105,7 +105,7 @@ ao_dma_set_transfer(uint8_t index, uint32_t ccr); void -ao_dma_set_isr(uint8_t index, void (*isr)(void)); +ao_dma_set_isr(uint8_t index, void (*isr)(int index)); void ao_dma_start(uint8_t index); @@ -130,17 +130,14 @@ ao_i2c_get(uint8_t i2c_index); uint8_t ao_i2c_start(uint8_t i2c_index, uint16_t address); -void -ao_i2c_stop(uint8_t i2c_index); - void ao_i2c_put(uint8_t i2c_index); -void -ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index); +uint8_t +ao_i2c_send(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); -void -ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index); +uint8_t +ao_i2c_recv(void *block, uint16_t len, uint8_t i2c_index, uint8_t stop); void ao_i2c_init(void); diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 0717be98..9ab001d7 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -23,6 +23,8 @@ struct ao_i2c_stm_info { struct stm_i2c *stm_i2c; }; +#define I2C_TIMEOUT 100 + #define I2C_IDLE 0 #define I2C_RUNNING 1 #define I2C_ERROR 2 @@ -47,7 +49,7 @@ uint8_t ao_i2c_mutex[STM_NUM_I2C]; (1 << STM_I2C_CR1_PE)) #define AO_STM_I2C_CR2 ((0 << STM_I2C_CR2_LAST) | \ - (1 << STM_I2C_CR2_DMAEN) | \ + (0 << STM_I2C_CR2_DMAEN) | \ (0 << STM_I2C_CR2_ITBUFEN) | \ (0 << STM_I2C_CR2_ITEVTEN) | \ (0 << STM_I2C_CR2_ITERREN) | \ @@ -66,20 +68,44 @@ static const struct ao_i2c_stm_info ao_i2c_stm_info[STM_NUM_I2C] = { }, }; +static uint8_t *ao_i2c_recv_data[STM_NUM_I2C]; +static uint16_t ao_i2c_recv_len[STM_NUM_I2C]; +static uint16_t ev_count; + static void ao_i2c_ev_isr(uint8_t index) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; uint32_t sr1; + ++ev_count; sr1 = stm_i2c->sr1; if (sr1 & (1 << STM_I2C_SR1_SB)) stm_i2c->dr = ao_i2c_addr[index]; if (sr1 & (1 << STM_I2C_SR1_ADDR)) { - (void) stm_i2c->sr2; + stm_i2c->cr2 &= ~(1 << STM_I2C_CR2_ITEVTEN); ao_i2c_state[index] = I2C_RUNNING; ao_wakeup(&ao_i2c_state[index]); } + if (sr1 & (1 << STM_I2C_SR1_BTF)) { + stm_i2c->cr2 &= ~(1 << STM_I2C_CR2_ITEVTEN); + ao_wakeup(&ao_i2c_state[index]); + } +#if 0 + if (sr1 & (1 << STM_I2C_SR1_RXNE)) { + if (ao_i2c_recv_len[index]) { + switch (--ao_i2c_recv_len[index]) { + case 0: + ao_wakeup(&ao_i2c_recv_len[index]); + break; + case 1: + stm_i2c->cr1 &= ~(1 << STM_I2C_CR1_ACK); + break; + } + *(ao_i2c_recv_data[index]++) = stm_i2c->dr; + } + } +#endif } void stm_i2c1_ev_isr(void) { ao_i2c_ev_isr(0); } @@ -118,38 +144,205 @@ ao_i2c_put(uint8_t index) ao_mutex_put(&ao_i2c_mutex[index]); } +static inline uint32_t in_sr1(char *where, struct stm_i2c *stm_i2c) { + uint32_t sr1 = stm_i2c->sr1; + printf("%s: sr1: %x\n", where, sr1); flush(); + return sr1; +} + +static inline uint32_t in_sr2(char *where, struct stm_i2c *stm_i2c) { + uint32_t sr2 = stm_i2c->sr2; + printf("%s: sr2: %x\n", where, sr2); flush(); + return sr2; +} + +static inline void out_cr1(char *where, struct stm_i2c *stm_i2c, uint32_t cr1) { + printf("%s: cr1: %x\n", where, cr1); flush(); + stm_i2c->cr1 = cr1; +} + +static inline uint32_t in_cr1(char *where, struct stm_i2c *stm_i2c) { + uint32_t cr1 = stm_i2c->cr1; + printf("%s: cr1: %x\n", where, cr1); flush(); + return cr1; +} + +static inline void out_cr2(char *where, struct stm_i2c *stm_i2c, uint32_t cr2) { + printf("%s: cr2: %x\n", where, cr2); flush(); + stm_i2c->cr2 = cr2; +} + +static inline uint32_t in_dr(char *where, struct stm_i2c *stm_i2c) { + uint32_t dr = stm_i2c->dr; + printf("%s: dr: %x\n", where, dr); flush(); + return dr; +} + +static inline void out_dr(char *where, struct stm_i2c *stm_i2c, uint32_t dr) { + printf("%s: dr: %x\n", where, dr); flush(); + stm_i2c->dr = dr; +} + uint8_t -ao_i2c_start(uint8_t index, uint16_t addr) +ao_i2c_check_status(char *where, uint8_t index, uint32_t sr1_want, uint32_t sr2_want) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; + uint32_t sr1_got, sr2_got; + + if (sr1_want) { + sr1_got = in_sr1(where, stm_i2c); + if ((sr1_got & sr1_want) != sr1_want) { + printf ("%s: sr1 wanted %x got %x\n", where, sr1_want, sr1_got); + return FALSE; + } + } + if (sr2_want) { + sr2_got = in_sr2(where, stm_i2c); + if ((sr2_got & sr2_want) != sr2_want) { + printf ("%s: sr1 wanted %x got %x\n", + where, sr2_want, sr2_got); + return FALSE; + } + } + printf ("%s: got sr1 %x and sr2 %x\n", where, sr1_want, sr2_want); + return TRUE; +} + +static uint8_t +ao_i2c_check_idle(uint8_t index) +{ + struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; + uint32_t s = 0; + int t; + for (t = 0; t < I2C_TIMEOUT; t++) { + if (!ao_i2c_check_status("check idle", index, + 0, + (1 << STM_I2C_SR2_BUSY))) + { + break; + } + ao_yield(); + } + if (t == I2C_TIMEOUT) + return FALSE; + return TRUE; +} + +uint8_t +ao_i2c_start(uint8_t index, uint16_t addr) +{ + struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; + uint32_t sr1, sr2; + int t; + +#if 0 + if (!ao_i2c_check_idle(index)) { + printf ("i2c busy\n"); + return FALSE; + } +#endif + ao_i2c_state[index] = I2C_IDLE; ao_i2c_addr[index] = addr; - stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN); - stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START); - ao_arch_critical( - while (ao_i2c_state[index] == I2C_IDLE) - ao_sleep(&ao_i2c_state[index]); - ); +#if 0 + out_cr2("start", stm_i2c, AO_STM_I2C_CR2); + out_cr1("start", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START)); + for (t = 0; t < I2C_TIMEOUT; t++) { + if (ao_i2c_check_status("waiting for start", + index, + (1 << STM_I2C_SR1_SB), + (1 << STM_I2C_SR2_BUSY) | + (1 << STM_I2C_SR2_MSL))) + break; + ao_yield(); + } + if (t == I2C_TIMEOUT) { + printf ("No start mode\n"); + return FALSE; + } + out_dr("address", stm_i2c, addr); + if (addr & 1) { + sr1 = (1 << STM_I2C_SR1_ADDR); + sr2 = (1 << STM_I2C_SR2_BUSY) | (1 << STM_I2C_SR2_MSL); + } else { + sr1 = (1 << STM_I2C_SR1_TXE) | (1 << STM_I2C_SR1_ADDR); + sr2 = (1 << STM_I2C_SR2_TRA) | (1 << STM_I2C_SR2_BUSY) | (1 << STM_I2C_SR2_MSL); + } + + for (t = 0; t < I2C_TIMEOUT; t++) { + if (ao_i2c_check_status("waiting for addr", + index, + sr1, sr2)) + break; + ao_yield(); + } + if (t == I2C_TIMEOUT) { + printf ("Set addr failed\n"); + return FALSE; + } + ao_i2c_state[index] = I2C_RUNNING; +#else + out_cr2("start", stm_i2c, AO_STM_I2C_CR2); + out_cr1("start", stm_i2c, + AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START)); + out_cr2("start", stm_i2c, + AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN)); + ao_alarm(1); + cli(); + while (ao_i2c_state[index] == I2C_IDLE) + if (ao_sleep(&ao_i2c_state[index])) + break; + sei(); + ao_clear_alarm(); +#endif return ao_i2c_state[index] == I2C_RUNNING; } -void +static void ao_i2c_stop(uint8_t index) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; ao_i2c_state[index] = I2C_IDLE; - stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); + out_cr2("enable isr", stm_i2c, + AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN)); + ev_count = 0; + out_cr1("stop", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + + /* XXX check to see if there is an interrupt here */ + while (in_cr1("stop", stm_i2c) & (1 << STM_I2C_CR1_STOP)) + ao_yield(); + printf ("ev_count in stop: %d\n", ev_count); } -void -ao_i2c_send(void *block, uint16_t len, uint8_t index) +uint8_t +ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; + uint8_t *b = block; + uint32_t sr1; + int t; + +#if 0 + while (len--) { + for (t = 0; t < I2C_TIMEOUT; t++) { + if (ao_i2c_check_status("send", index, + (1 << STM_I2C_SR1_TXE), + 0)) + break; + ao_yield(); + } + if (t == I2C_TIMEOUT) + return FALSE; + out_dr("send", stm_i2c, *b++); + } +#else uint8_t tx_dma_index = ao_i2c_stm_info[index].tx_dma_index; - stm_i2c->cr2 &= ~(1 << STM_I2C_CR2_LAST); + /* Clear any pending ADDR bit */ + in_sr2("send clear addr", stm_i2c); + out_cr2("send", stm_i2c, AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN)); ao_dma_set_transfer(tx_dma_index, &stm_i2c->dr, block, @@ -164,20 +357,104 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); ao_dma_start(tx_dma_index); - ao_arch_critical( - while (!ao_dma_done[tx_dma_index]) - ao_sleep(&ao_dma_done[tx_dma_index]); - ); + ao_alarm(1 + len); + cli(); + while (!ao_dma_done[tx_dma_index]) + if (ao_sleep(&ao_dma_done[tx_dma_index])) { + printf ("send timeout\n"); + break; + } ao_dma_done_transfer(tx_dma_index); + out_cr2("send enable isr", stm_i2c, + AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN)); + while ((in_sr1("send_btf", stm_i2c) & (1 << STM_I2C_SR1_BTF)) == 0) + if (ao_sleep(&ao_i2c_state[index])) + break; + out_cr2("send disable isr", stm_i2c, AO_STM_I2C_CR2); + sei(); +#endif + if (stop) + ao_i2c_stop(index); + return TRUE; } void -ao_i2c_recv(void *block, uint16_t len, uint8_t index) +ao_i2c_recv_dma_isr(int index) +{ + int i; + struct stm_i2c *stm_i2c = NULL; + + for (i = 0; i < STM_NUM_I2C; i++) + if (index == ao_i2c_stm_info[i].rx_dma_index) { + stm_i2c = ao_i2c_stm_info[i].stm_i2c; + break; + } + if (!stm_i2c) + return; + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_LAST); + ao_dma_done[index] = 1; + ao_wakeup(&ao_dma_done[index]); +} + +uint8_t +ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; - uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index; + uint8_t *b = block; + int t; + + switch (len) { + case 0: + return TRUE; + case 1: + out_cr1("setup recv 1", stm_i2c, AO_STM_I2C_CR1); + /* Clear any pending ADDR bit */ + in_sr2("clear addr", stm_i2c); + out_cr1("setup recv 1", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + break; + case 2: + /* Clear any pending ADDR bit */ + out_cr1("setup recv 2", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_POS)); + if (in_sr1("clear addr", stm_i2c) & (1 << STM_I2C_SR1_ADDR)) + in_sr2("clear addr", stm_i2c); + out_cr1("setup recv 1", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + break; + default: +// out_cr1("setup recv 2", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK) | (1 << STM_I2C_CR1_POS)); + out_cr1("setup recv 2", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK)); + /* Clear any pending ADDR bit */ + if (in_sr1("clear addr", stm_i2c) & (1 << STM_I2C_SR1_ADDR)) + in_sr2("clear addr", stm_i2c); + break; + } + + while (len--) { + for (t = 0; t < I2C_TIMEOUT; t++) { + if (in_sr1("recv", stm_i2c) & (1 << STM_I2C_SR1_RXNE)) + break; + ao_yield(); + } + if (t == I2C_TIMEOUT) + return FALSE; + *b++ = in_dr("recv", stm_i2c); + if (len == 2 && stop) { + out_cr1("clear ack", stm_i2c, +// AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP) | (1 << STM_I2C_CR1_POS)); + AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + } + } + if (stop) { + for (t = 0; t < I2C_TIMEOUT; t++) { + if (!(in_cr1("recv stop", stm_i2c) & (1 << STM_I2C_CR1_STOP))) + break; + ao_yield(); + } + if (t == I2C_TIMEOUT) + return FALSE; + } - stm_i2c->cr2 |= (1 << STM_I2C_CR2_LAST); +#if 0 + uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index; ao_dma_set_transfer(rx_dma_index, &stm_i2c->dr, block, @@ -190,6 +467,13 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index) (0 << STM_DMA_CCR_PINC) | (0 << STM_DMA_CCR_CIRC) | (STM_DMA_CCR_DIR_PER_TO_MEM << STM_DMA_CCR_DIR)); + if (len >= 2) { + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK) | (1 << STM_I2C_CR1_POS); + stm_i2c->cr2 = AO_STM_I2C_CR2; + } else { + stm_i2c->cr1 = AO_STM_I2C_CR1; + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_LAST); + } ao_dma_start(rx_dma_index); cli(); @@ -197,6 +481,7 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index) ao_sleep(&ao_dma_done[rx_dma_index]); sei(); ao_dma_done_transfer(rx_dma_index); +#endif } void @@ -219,6 +504,7 @@ ao_i2c_channel_init(uint8_t index) (0 << STM_I2C_CCR_DUTY) | (20 << STM_I2C_CCR_CCR)); + stm_i2c->cr1 = AO_STM_I2C_CR1; }