X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fstm%2Fao_i2c_stm.c;h=c205706d37669390bfec37081031abfd6bd61b6f;hp=0717be98164e0cf820b9c3d2f262bdbf59ae325f;hb=97317d332f21c42860747c4ecde633bd0228ef52;hpb=0266e08dbf19e2204fb5f758d5d0f944d2afff7d diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 0717be98..c205706d 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,36 @@ 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 (sr1 & (1 << STM_I2C_SR1_RXNE)) { + if (ao_i2c_recv_len[index]) { + *(ao_i2c_recv_data[index]++) = stm_i2c->dr; + if (!--ao_i2c_recv_len[index]) + ao_wakeup(&ao_i2c_recv_len[index]); + } + } } void stm_i2c1_ev_isr(void) { ao_i2c_ev_isr(0); } @@ -118,38 +136,103 @@ ao_i2c_put(uint8_t index) ao_mutex_put(&ao_i2c_mutex[index]); } +#define I2C_DEBUG 0 +#if I2C_DEBUG +#define DBG(x...) printf(x) +#else +#define DBG(x...) +#endif + +static inline uint32_t in_sr1(char *where, struct stm_i2c *stm_i2c) { + uint32_t sr1 = stm_i2c->sr1; + DBG("%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; + DBG("%s: sr2: %x\n", where, sr2); flush(); + return sr2; +} + +static inline void out_cr1(char *where, struct stm_i2c *stm_i2c, uint32_t cr1) { + DBG("%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; + DBG("%s: cr1: %x\n", where, cr1); flush(); + return cr1; +} + +static inline void out_cr2(char *where, struct stm_i2c *stm_i2c, uint32_t cr2) { + DBG("%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; + DBG("%s: dr: %x\n", where, dr); flush(); + return dr; +} + +static inline void out_dr(char *where, struct stm_i2c *stm_i2c, uint32_t dr) { + DBG("%s: dr: %x\n", where, dr); flush(); + stm_i2c->dr = dr; +} + 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; + 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]); - ); + 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(); return ao_i2c_state[index] == I2C_RUNNING; } -void -ao_i2c_stop(uint8_t index) +static void +ao_i2c_wait_stop(uint8_t index) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; - + int t; + + for (t = 0; t < I2C_TIMEOUT; t++) { + if (!(in_cr1("wait stop", stm_i2c) & (1 << STM_I2C_CR1_STOP))) + break; + ao_yield(); + } ao_i2c_state[index] = I2C_IDLE; - stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); } -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; + 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,47 +247,127 @@ 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])) + break; + ao_clear_alarm(); 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(); + if (stop) { + out_cr1("stop", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + ao_i2c_wait_stop(index); + } + return TRUE; } void -ao_i2c_recv(void *block, uint16_t len, uint8_t index) +ao_i2c_recv_dma_isr(int index) { - 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; + 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]); +} - stm_i2c->cr2 |= (1 << STM_I2C_CR2_LAST); - ao_dma_set_transfer(rx_dma_index, - &stm_i2c->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)); - - ao_dma_start(rx_dma_index); - cli(); - while (!ao_dma_done[rx_dma_index]) - ao_sleep(&ao_dma_done[rx_dma_index]); - sei(); - ao_dma_done_transfer(rx_dma_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 *b = block; + int t; + uint8_t ret = TRUE; + + if (len == 0) + return TRUE; + if (len == 1) { + ao_i2c_recv_data[index] = block; + ao_i2c_recv_len[index] = 1; + out_cr1("setup recv 1", stm_i2c, AO_STM_I2C_CR1); + + /* Clear any pending ADDR bit */ + in_sr2("clear addr", stm_i2c); + + /* Enable interrupts to transfer the byte */ + out_cr2("setup recv 1", stm_i2c, + AO_STM_I2C_CR2 | + (1 << STM_I2C_CR2_ITEVTEN) | + (1 << STM_I2C_CR2_ITERREN) | + (1 << STM_I2C_CR2_ITBUFEN)); + if (stop) + out_cr1("setup recv 1", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + + ao_alarm(1); + cli(); + while (ao_i2c_recv_len[index]) + if (ao_sleep(&ao_i2c_recv_len[index])) + break; + sei(); + ret = ao_i2c_recv_len[index] == 0; + ao_clear_alarm(); + } else { + uint8_t rx_dma_index = ao_i2c_stm_info[index].rx_dma_index; + ao_dma_set_transfer(rx_dma_index, + &stm_i2c->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)); + out_cr1("recv > 1", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK)); + out_cr2("recv > 1", stm_i2c, AO_STM_I2C_CR2 | + (1 << STM_I2C_CR2_DMAEN) | (1 << STM_I2C_CR2_LAST)); + /* Clear any pending ADDR bit */ + in_sr2("clear addr", stm_i2c); + + ao_dma_start(rx_dma_index); + ao_alarm(len); + cli(); + while (!ao_dma_done[rx_dma_index]) + if (ao_sleep(&ao_dma_done[rx_dma_index])) + break; + sei(); + ao_clear_alarm(); + ret = ao_dma_done[rx_dma_index]; + ao_dma_done_transfer(rx_dma_index); + out_cr1("stop recv > 1", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + } + if (stop) + ao_i2c_wait_stop(index); + return ret; } void ao_i2c_channel_init(uint8_t index) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; + int i; /* Turn I2C off while configuring */ + stm_i2c->cr1 = (1 << STM_I2C_CR1_SWRST); + for (i = 0; i < 100; i++) + asm("nop"); stm_i2c->cr1 = 0; stm_i2c->cr2 = AO_STM_I2C_CR2; @@ -219,6 +382,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; }