X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fstm%2Fao_i2c_stm.c;h=4d7d8d87a37fff150c6418f7f328060504bf0305;hp=9ab001d70082412d307dcbb88f6f3a2ec5b7da77;hb=1a1d4a557a30e2e743936b828b654187ec562ca8;hpb=0f0cc91ce8e9807dca48a5c0c53d821f5060e245 diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index 9ab001d7..4d7d8d87 100644 --- a/src/stm/ao_i2c_stm.c +++ b/src/stm/ao_i2c_stm.c @@ -33,6 +33,22 @@ static uint8_t ao_i2c_state[STM_NUM_I2C]; static uint16_t ao_i2c_addr[STM_NUM_I2C]; uint8_t ao_i2c_mutex[STM_NUM_I2C]; +#if AO_PCLK1 == 2000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_2_MHZ +#endif +#if AO_PCLK1 == 4000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_4_MHZ +#endif +#if AO_PCLK1 == 8000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_8_MHZ +#endif +#if AO_PCLK1 == 16000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_16_MHZ +#endif +#if AO_PCLK1 == 32000000 +# define AO_STM_I2C_CR2_FREQ STM_I2C_CR2_FREQ_32_MHZ +#endif + #define AO_STM_I2C_CR1 ((0 << STM_I2C_CR1_SWRST) | \ (0 << STM_I2C_CR1_ALERT) | \ (0 << STM_I2C_CR1_PEC) | \ @@ -53,7 +69,7 @@ uint8_t ao_i2c_mutex[STM_NUM_I2C]; (0 << STM_I2C_CR2_ITBUFEN) | \ (0 << STM_I2C_CR2_ITEVTEN) | \ (0 << STM_I2C_CR2_ITERREN) | \ - (STM_I2C_CR2_FREQ_16_MHZ << STM_I2C_CR2_FREQ)) + (AO_STM_I2C_CR2_FREQ << STM_I2C_CR2_FREQ)) static const struct ao_i2c_stm_info ao_i2c_stm_info[STM_NUM_I2C] = { { @@ -91,21 +107,13 @@ ao_i2c_ev_isr(uint8_t index) 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; + if (!--ao_i2c_recv_len[index]) + ao_wakeup(&ao_i2c_recv_len[index]); } } -#endif } void stm_i2c1_ev_isr(void) { ao_i2c_ev_isr(0); } @@ -144,91 +152,6 @@ 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_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) { @@ -236,84 +159,37 @@ ao_i2c_start(uint8_t index, uint16_t addr) 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; -#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); - } - + stm_i2c->cr2 = AO_STM_I2C_CR2; + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_START); for (t = 0; t < I2C_TIMEOUT; t++) { - if (ao_i2c_check_status("waiting for addr", - index, - sr1, sr2)) + if (!(stm_i2c->cr1 & (1 << STM_I2C_CR1_START))) 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); + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN); + ao_alarm(AO_MS_TO_TICKS(250)); 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; } static void -ao_i2c_stop(uint8_t index) +ao_i2c_wait_stop(uint8_t index) { struct stm_i2c *stm_i2c = ao_i2c_stm_info[index].stm_i2c; - - ao_i2c_state[index] = I2C_IDLE; - 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)); + int t; - /* XXX check to see if there is an interrupt here */ - while (in_cr1("stop", stm_i2c) & (1 << STM_I2C_CR1_STOP)) + for (t = 0; t < I2C_TIMEOUT; t++) { + if (!(stm_i2c->cr1 & (1 << STM_I2C_CR1_STOP))) + break; ao_yield(); - printf ("ev_count in stop: %d\n", ev_count); + } + ao_i2c_state[index] = I2C_IDLE; } uint8_t @@ -322,27 +198,11 @@ 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; /* 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)); + (void) stm_i2c->sr2; + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN); ao_dma_set_transfer(tx_dma_index, &stm_i2c->dr, block, @@ -360,21 +220,20 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop) 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"); + 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) + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN); + while ((stm_i2c->sr1 & (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); + stm_i2c->cr2 = AO_STM_I2C_CR2; sei(); -#endif - if (stop) - ao_i2c_stop(index); + if (stop) { + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); + ao_i2c_wait_stop(index); + } return TRUE; } @@ -402,94 +261,81 @@ 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; - switch (len) { - case 0: + if (len == 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: + if (len == 1) { + ao_i2c_recv_data[index] = block; + ao_i2c_recv_len[index] = 1; + stm_i2c->cr1 = AO_STM_I2C_CR1; + /* 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)); + stm_i2c->sr2; + + /* Enable interrupts to transfer the byte */ + stm_i2c->cr2 = (AO_STM_I2C_CR2 | + (1 << STM_I2C_CR2_ITEVTEN) | + (1 << STM_I2C_CR2_ITERREN) | + (1 << STM_I2C_CR2_ITBUFEN)); + if (stop) + stm_i2c->cr1 = 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)); + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_ACK); + stm_i2c->cr2 = AO_STM_I2C_CR2 | + (1 << STM_I2C_CR2_DMAEN) | (1 << STM_I2C_CR2_LAST); /* Clear any pending ADDR bit */ - if (in_sr1("clear addr", stm_i2c) & (1 << STM_I2C_SR1_ADDR)) - in_sr2("clear addr", stm_i2c); - break; - } + (void) stm_i2c->sr2; - 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))) + 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; - ao_yield(); - } - if (t == I2C_TIMEOUT) - return FALSE; - } - -#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, - 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)); - 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); + sei(); + ao_clear_alarm(); + ret = ao_dma_done[rx_dma_index]; + ao_dma_done_transfer(rx_dma_index); + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); } - - 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); -#endif + 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; @@ -551,4 +397,3 @@ ao_i2c_init(void) stm_nvic_set_priority(STM_ISR_I2C2_ER_POS, 3); #endif } -