X-Git-Url: https://git.gag.com/?p=fw%2Faltos;a=blobdiff_plain;f=src%2Fstm%2Fao_i2c_stm.c;h=158f5b218ebfe0edd877b4049322fb11b51f18fd;hp=d82342db14e500631850729adec5cb061e401ad8;hb=4af4e36cda96d053458eeb040e35886890917385;hpb=47bc9b2a39b7a8d3ef3fe8acc7fbf0512695e548 diff --git a/src/stm/ao_i2c_stm.c b/src/stm/ao_i2c_stm.c index d82342db..158f5b21 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_FAST 1 + #define I2C_TIMEOUT 100 #define I2C_IDLE 0 @@ -33,6 +35,49 @@ 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]; +# define I2C_HIGH_SLOW 5000 /* ns, 100kHz clock */ +#ifdef TELEMEGA +# define I2C_HIGH_FAST 2000 /* ns, 167kHz clock */ +#else +# define I2C_HIGH_FAST 1000 /* ns, 333kHz clock */ +#endif + +# define I2C_RISE_SLOW 500 /* ns */ +# define I2C_RISE_FAST 100 /* ns */ + +/* Clock period in ns */ +#define CYCLES(period) (((period) * (AO_PCLK1 / 1000)) / 1000000) + +#define max(a,b) ((a) > (b) ? (a) : (b)) +#define I2C_CCR_HIGH_SLOW max(4,CYCLES(I2C_HIGH_SLOW)) +#define I2C_CCR_HIGH_FAST max(4,CYCLES(I2C_HIGH_FAST)) +#define I2C_TRISE_SLOW (CYCLES(I2C_RISE_SLOW) + 1) +#define I2C_TRISE_FAST (CYCLES(I2C_RISE_FAST) + 1) + +#if I2C_FAST +#define I2C_TRISE I2C_TRISE_FAST +#define I2C_CCR_HIGH I2C_CCR_HIGH_FAST +#else +#define I2C_TRISE I2C_TRISE_SLOW +#define I2C_CCR_HIGH I2C_CCR_HIGH_SLOW +#endif + +#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 +98,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] = { { @@ -136,73 +181,27 @@ 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; - 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(); + 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 (!(stm_i2c->cr1 & (1 << STM_I2C_CR1_START))) + break; + } + ao_arch_block_interrupts(); + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_ITEVTEN) | (1 << STM_I2C_CR2_ITERREN); + ao_i2c_ev_isr(index); while (ao_i2c_state[index] == I2C_IDLE) - if (ao_sleep(&ao_i2c_state[index])) + if (ao_sleep_for(&ao_i2c_state[index], AO_MS_TO_TICKS(250))) break; - sei(); - ao_clear_alarm(); + ao_arch_release_interrupts(); return ao_i2c_state[index] == I2C_RUNNING; } @@ -213,26 +212,36 @@ ao_i2c_wait_stop(uint8_t index) int t; for (t = 0; t < I2C_TIMEOUT; t++) { - if (!(in_cr1("wait stop", stm_i2c) & (1 << STM_I2C_CR1_STOP))) + if (!(stm_i2c->cr1 & (1 << STM_I2C_CR1_STOP))) break; ao_yield(); } ao_i2c_state[index] = I2C_IDLE; } +static void +ao_i2c_wait_addr(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 (!(stm_i2c->sr1 & (1 << STM_I2C_SR1_ADDR))) + break; + if (t) + printf ("wait_addr %d\n", t); +} + 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; /* 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; + ao_i2c_wait_addr(index); + stm_i2c->cr2 = AO_STM_I2C_CR2 | (1 << STM_I2C_CR2_DMAEN); ao_dma_set_transfer(tx_dma_index, &stm_i2c->dr, block, @@ -247,22 +256,19 @@ ao_i2c_send(void *block, uint16_t len, uint8_t index, uint8_t stop) (STM_DMA_CCR_DIR_MEM_TO_PER << STM_DMA_CCR_DIR)); ao_dma_start(tx_dma_index); - ao_alarm(1 + len); - cli(); + ao_arch_block_interrupts(); while (!ao_dma_done[tx_dma_index]) - if (ao_sleep(&ao_dma_done[tx_dma_index])) + if (ao_sleep_for(&ao_dma_done[tx_dma_index], 1 + len)) 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])) + 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_for(&ao_i2c_state[index], 1 + len)) break; - out_cr2("send disable isr", stm_i2c, AO_STM_I2C_CR2); - sei(); + stm_i2c->cr2 = AO_STM_I2C_CR2; + ao_arch_release_interrupts(); if (stop) { - out_cr1("stop", stm_i2c, AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP)); + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); ao_i2c_wait_stop(index); } return TRUE; @@ -290,8 +296,6 @@ 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) @@ -299,28 +303,26 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop) 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); + stm_i2c->cr1 = AO_STM_I2C_CR1; /* Clear any pending ADDR bit */ - in_sr2("clear addr", stm_i2c); + stm_i2c->sr2; + ao_i2c_wait_addr(index); /* 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)); + stm_i2c->cr2 = (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)); + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); - ao_alarm(1); - cli(); + ao_arch_block_interrupts(); while (ao_i2c_recv_len[index]) - if (ao_sleep(&ao_i2c_recv_len[index])) + if (ao_sleep_for(&ao_i2c_recv_len[index], 1)) break; - sei(); + ao_arch_release_interrupts(); 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, @@ -335,23 +337,22 @@ ao_i2c_recv(void *block, uint16_t len, uint8_t index, uint8_t stop) (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)); + 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 */ - in_sr2("clear addr", stm_i2c); + (void) stm_i2c->sr2; + ao_i2c_wait_addr(index); ao_dma_start(rx_dma_index); - ao_alarm(len); - cli(); + ao_arch_block_interrupts(); while (!ao_dma_done[rx_dma_index]) - if (ao_sleep(&ao_dma_done[rx_dma_index])) + if (ao_sleep_for(&ao_dma_done[rx_dma_index], len)) break; - sei(); - ao_clear_alarm(); + ao_arch_release_interrupts(); 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)); + stm_i2c->cr1 = AO_STM_I2C_CR1 | (1 << STM_I2C_CR1_STOP); } if (stop) ao_i2c_wait_stop(index); @@ -362,8 +363,12 @@ 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; @@ -374,14 +379,23 @@ ao_i2c_channel_init(uint8_t index) stm_i2c->sr1 = 0; stm_i2c->sr2 = 0; - stm_i2c->ccr = ((1 << STM_I2C_CCR_FS) | + stm_i2c->ccr = ((I2C_FAST << STM_I2C_CCR_FS) | (0 << STM_I2C_CCR_DUTY) | - (20 << STM_I2C_CCR_CCR)); - + (I2C_CCR_HIGH << STM_I2C_CCR_CCR)); + + stm_i2c->trise = I2C_TRISE; stm_i2c->cr1 = AO_STM_I2C_CR1; } +static inline void +i2c_pin_set(struct stm_gpio *gpio, int pin) +{ + stm_afr_set(gpio, pin, STM_AFR_AF4); + stm_ospeedr_set(gpio, pin, STM_OSPEEDR_400kHz); + stm_pupdr_set(gpio, pin, STM_PUPDR_PULL_UP); +} + void ao_i2c_init(void) { @@ -389,12 +403,12 @@ ao_i2c_init(void) stm_rcc.ahbenr |= (1 << STM_RCC_AHBENR_GPIOBEN); #if HAS_I2C_1 # if I2C_1_PB6_PB7 - stm_afr_set(&stm_gpiob, 6, STM_AFR_AF4); - stm_afr_set(&stm_gpiob, 7, STM_AFR_AF4); + i2c_pin_set(&stm_gpiob, 6); + i2c_pin_set(&stm_gpiob, 7); # else # if I2C_1_PB8_PB9 - stm_afr_set(&stm_gpiob, 8, STM_AFR_AF4); - stm_afr_set(&stm_gpiob, 9, STM_AFR_AF4); + i2c_pin_set(&stm_gpiob, 8); + i2c_pin_set(&stm_gpiob, 9); # else # error "No I2C_1 port configuration specified" # endif @@ -404,15 +418,15 @@ ao_i2c_init(void) ao_i2c_channel_init(0); stm_nvic_set_enable(STM_ISR_I2C1_EV_POS); - stm_nvic_set_priority(STM_ISR_I2C1_EV_POS, 3); + stm_nvic_set_priority(STM_ISR_I2C1_EV_POS, AO_STM_NVIC_MED_PRIORITY); stm_nvic_set_enable(STM_ISR_I2C1_ER_POS); - stm_nvic_set_priority(STM_ISR_I2C1_ER_POS, 3); + stm_nvic_set_priority(STM_ISR_I2C1_ER_POS, AO_STM_NVIC_MED_PRIORITY); #endif #if HAS_I2C_2 # if I2C_2_PB10_PB11 - stm_afr_set(&stm_gpiob, 10, STM_AFR_AF4); - stm_afr_set(&stm_gpiob, 11, STM_AFR_AF4); + i2c_pin_set(&stm_gpiob, 10); + i2c_pin_set(&stm_gpiob, 11); # else # error "No I2C_2 port configuration specified" # endif @@ -420,9 +434,8 @@ ao_i2c_init(void) ao_i2c_channel_init(1); stm_nvic_set_enable(STM_ISR_I2C2_EV_POS); - stm_nvic_set_priority(STM_ISR_I2C2_EV_POS, 3); + stm_nvic_set_priority(STM_ISR_I2C2_EV_POS, AO_STM_NVIC_MED_PRIORITY); stm_nvic_set_enable(STM_ISR_I2C2_ER_POS); - stm_nvic_set_priority(STM_ISR_I2C2_ER_POS, 3); + stm_nvic_set_priority(STM_ISR_I2C2_ER_POS, AO_STM_NVIC_MED_PRIORITY); #endif } -