summaryrefslogtreecommitdiffstats
path: root/stm32/app/i2c_hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm32/app/i2c_hw.c')
-rw-r--r--stm32/app/i2c_hw.c360
1 files changed, 360 insertions, 0 deletions
diff --git a/stm32/app/i2c_hw.c b/stm32/app/i2c_hw.c
new file mode 100644
index 0000000..a17c564
--- /dev/null
+++ b/stm32/app/i2c_hw.c
@@ -0,0 +1,360 @@
+#include "project.h"
+
+
+#define SCL1 GPIO6
+#define SDA1 GPIO7
+#define SCL1_PORT GPIOB
+#define SDA1_PORT GPIOB
+
+#define SCL2 GPIO10
+#define SDA2 GPIO11
+#define SCL2_PORT GPIOB
+#define SDA2_PORT GPIOB
+
+void
+i2c_clear_start (uint32_t i2c)
+{
+ I2C_CR1 (i2c) &= ~ (uint32_t) I2C_CR1_START;
+}
+
+
+int
+i2cp_start (uint32_t i2c)
+{
+ uint32_t timeout = 1000;
+ i2c_send_start (i2c);
+
+ while (! ((I2C_SR1 (i2c) & I2C_SR1_SB)
+ & (I2C_SR2 (i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY))) && (timeout--));
+
+ return timeout ? 0 : -1;
+}
+
+void
+i2cp_abort_start (uint32_t i2c)
+{
+ i2c_clear_start (i2c);
+ delay_us (10);
+}
+
+void
+i2cp_stop (uint32_t i2c)
+{
+ i2c_send_stop (i2c);
+}
+
+
+void
+i2cp_abort_stop (uint32_t i2c)
+{
+ i2c_clear_stop (i2c);
+ delay_us (10);
+}
+
+int
+i2cp_send (uint32_t i2c, uint8_t v)
+{
+ uint32_t reg;
+ uint32_t timeout = 1000;
+
+ i2c_send_data (i2c, v);
+
+ while (!
+ ((reg =
+ I2C_SR1 (i2c)) & (I2C_SR1_BTF | I2C_SR1_BERR | I2C_SR1_ARLO |
+ I2C_SR1_AF | I2C_SR1_PECERR | I2C_SR1_TIMEOUT |
+ I2C_SR1_SMBALERT)) && (timeout--));
+
+ I2C_SR1 (i2c) =
+ reg & ~ (I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_PECERR |
+ I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT);
+
+ if (!timeout)
+ return 1;
+
+
+ return (reg & I2C_SR1_BTF) ? 0 : -1;
+}
+
+/*0 on success 1 on failure*/
+int
+i2cp_start_transaction (uint32_t i2c, uint8_t a, int wnr)
+{
+ uint32_t reg;
+ uint32_t __attribute__ ((unused)) dummy;
+ uint32_t timeout = 1000;
+
+ i2c_send_start (i2c);
+
+ while (! ((I2C_SR1 (i2c) & I2C_SR1_SB)
+ & (I2C_SR2 (i2c) & (I2C_SR2_MSL | I2C_SR2_BUSY))) && (timeout--));
+
+ if (!timeout)
+ return -1;
+
+ i2c_send_7bit_address (i2c, a, wnr);
+
+ while (!
+ ((reg =
+ I2C_SR1 (i2c)) & (I2C_SR1_ADDR | I2C_SR1_BERR | I2C_SR1_ARLO |
+ I2C_SR1_AF | I2C_SR1_PECERR | I2C_SR1_TIMEOUT |
+ I2C_SR1_SMBALERT)) && (timeout--));
+
+ if (!timeout)
+ return -1;
+
+ dummy = I2C_SR2 (i2c);
+
+ I2C_SR1 (i2c) =
+ reg & ~ (I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_PECERR |
+ I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT);
+
+
+ return (reg == 0x82) ? 0 : -1;
+}
+
+
+/*This is stupid, it bit bangs a dummy transaction to get the host i2c controller back in the game */
+void
+i2cp1_reset_sm (void)
+{
+ int i;
+
+ MAP_OUTPUT_PP (SCL1);
+ MAP_OUTPUT_PP (SDA1);
+
+ SET (SDA1);
+ SET (SCL1);
+ delay_us (10);
+ CLEAR (SDA1);
+ delay_us (10);
+ CLEAR (SCL1);
+
+ for (i = 0; i < 9; ++i) {
+ delay_us (10);
+ SET (SCL1);
+ delay_us (10);
+ CLEAR (SCL1);
+ delay_us (10);
+ }
+
+ SET (SCL1);
+ delay_us (10);
+ SET (SDA1);
+ delay_us (10);
+
+ MAP_AF_OD (SCL1);
+ MAP_AF_OD (SDA1);
+
+}
+
+void
+i2cp2_reset_sm (void)
+{
+ int i;
+
+ MAP_OUTPUT_PP (SCL2);
+ MAP_OUTPUT_PP (SDA2);
+
+ SET (SDA2);
+ SET (SCL2);
+ delay_us (10);
+ CLEAR (SDA2);
+ delay_us (10);
+ CLEAR (SCL2);
+
+ for (i = 0; i < 9; ++i) {
+ delay_us (10);
+ SET (SCL2);
+ delay_us (10);
+ CLEAR (SCL2);
+ delay_us (10);
+ }
+
+ SET (SCL2);
+ delay_us (10);
+ SET (SDA2);
+ delay_us (10);
+
+ MAP_AF_OD (SCL2);
+ MAP_AF_OD (SDA2);
+
+}
+
+
+
+void
+i2cp1_start_dma (uint8_t *buf, int len)
+{
+ dma_channel_reset (DMA1, DMA_CHANNEL6);
+ dma_set_peripheral_address (DMA1, DMA_CHANNEL6, (uint32_t) & I2C1_DR);
+ dma_set_memory_address (DMA1, DMA_CHANNEL6, (uint32_t) buf);
+ dma_set_number_of_data (DMA1, DMA_CHANNEL6, len);
+ dma_set_read_from_memory (DMA1, DMA_CHANNEL6);
+ dma_enable_memory_increment_mode (DMA1, DMA_CHANNEL6);
+ dma_set_peripheral_size (DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
+ dma_set_memory_size (DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
+ dma_set_priority (DMA1, DMA_CHANNEL6, DMA_CCR_PL_MEDIUM);
+ dma_enable_transfer_complete_interrupt (DMA1, DMA_CHANNEL6);
+ dma_enable_transfer_error_interrupt (DMA1, DMA_CHANNEL6);
+ dma_enable_channel (DMA1, DMA_CHANNEL6);
+
+ i2c_enable_dma (I2C1);
+}
+
+
+void
+i2cp2_start_dma (uint8_t *buf, int len)
+{
+ dma_channel_reset (DMA1, DMA_CHANNEL4);
+ dma_set_peripheral_address (DMA1, DMA_CHANNEL4, (uint32_t) & I2C2_DR);
+ dma_set_memory_address (DMA1, DMA_CHANNEL4, (uint32_t) buf);
+ dma_set_number_of_data (DMA1, DMA_CHANNEL4, len);
+ dma_set_read_from_memory (DMA1, DMA_CHANNEL4);
+ dma_enable_memory_increment_mode (DMA1, DMA_CHANNEL4);
+ dma_set_peripheral_size (DMA1, DMA_CHANNEL4, DMA_CCR_PSIZE_8BIT);
+ dma_set_memory_size (DMA1, DMA_CHANNEL4, DMA_CCR_MSIZE_8BIT);
+ dma_set_priority (DMA1, DMA_CHANNEL4, DMA_CCR_PL_MEDIUM);
+ dma_enable_transfer_complete_interrupt (DMA1, DMA_CHANNEL4);
+ dma_enable_transfer_error_interrupt (DMA1, DMA_CHANNEL4);
+ dma_enable_channel (DMA1, DMA_CHANNEL4);
+
+ i2c_enable_dma (I2C2);
+}
+
+
+int
+i2cp1_dma_in_progress (void)
+{
+ return ! (DMA1_ISR & (DMA_ISR_TCIF6 | DMA_ISR_TEIF6));
+}
+
+int
+i2cp2_dma_in_progress (void)
+{
+ return ! (DMA1_ISR & (DMA_ISR_TCIF4 | DMA_ISR_TEIF4));
+}
+
+void
+i2cp1_stop_dma (void)
+{
+ DMA1_IFCR |= DMA_IFCR_CTCIF6 | DMA_IFCR_CTEIF6 | DMA_IFCR_CGIF6;
+
+ dma_disable_transfer_complete_interrupt (DMA1, DMA_CHANNEL6);
+ dma_disable_transfer_error_interrupt (DMA1, DMA_CHANNEL6);
+
+ i2c_disable_dma (I2C1);
+ dma_disable_channel (DMA1, DMA_CHANNEL6);
+}
+
+void
+i2cp2_stop_dma (void)
+{
+ DMA1_IFCR |= DMA_IFCR_CTCIF4 | DMA_IFCR_CTEIF4 | DMA_IFCR_CGIF4;
+
+ dma_disable_transfer_complete_interrupt (DMA1, DMA_CHANNEL4);
+ dma_disable_transfer_error_interrupt (DMA1, DMA_CHANNEL4);
+
+ i2c_disable_dma (I2C2);
+ dma_disable_channel (DMA1, DMA_CHANNEL4);
+}
+
+
+void
+i2cp_reset (uint32_t i2c)
+{
+ while (i2c_lock());
+
+ i2cp_start (i2c);
+ i2cp_abort_start (i2c);
+ i2cp_stop (i2c);
+ i2cp_abort_stop (i2c);
+
+ i2cp_start (i2c);
+ i2cp_abort_start (i2c);
+ i2cp_stop (i2c);
+ i2cp_abort_stop (i2c);
+ i2c_unlock();
+}
+
+
+
+void
+i2cp_scan (uint32_t i2c)
+{
+ int i, r;
+
+ i2cp_reset (i2c);
+
+ printf ("Probing bus\n");
+
+ for (i = 0; i < 128; ++i) {
+ printf ("%d\n", i);
+
+ while (i2c_lock());
+
+ i2cp_start (i2c);
+ i2cp_abort_start (i2c);
+ i2cp_stop (i2c);
+ i2cp_abort_stop (i2c);
+ delay_ms (10);
+ r = i2cp_start_transaction (i2c, i, I2C_WRITE);
+ i2cp_stop (i2c);
+ i2c_unlock();
+
+ if (!r)
+ printf ("Found device at address 0x%x\n", i);
+
+ usart1_drain();
+ }
+
+ printf ("Done\n");
+ i2cp_reset (i2c);
+
+}
+
+static void
+i2cp_bringup (uint32_t i2c)
+{
+ i2c_peripheral_enable (i2c);
+ i2c_clear_start (i2c);
+ i2c_clear_stop (i2c);
+ i2c_reset (i2c);
+ i2c_peripheral_enable (i2c);
+
+ I2C_CR1 (i2c) |= I2C_CR1_SWRST;
+ delay_us (1000);
+ I2C_CR1 (i2c) &= ~I2C_CR1_SWRST;
+
+
+ if (i2c == I2C1)
+ i2cp1_reset_sm();
+ else
+ i2cp2_reset_sm();
+
+
+ i2c_set_clock_frequency (i2c, I2C_CR2_FREQ_36MHZ);
+ i2c_set_standard_mode (i2c);
+ i2c_set_ccr (i2c, 0x80); /* t_high=t_high=CCR * Tpclk1 */
+ i2c_set_trise (i2c, 0x0b);
+
+ i2c_set_own_7bit_slave_address (i2c, 0x00);
+
+ i2c_peripheral_enable (i2c);
+}
+
+
+void
+i2cp_init (void)
+{
+ rcc_periph_clock_enable (RCC_I2C1);
+ rcc_periph_clock_enable (RCC_I2C2);
+ rcc_periph_clock_enable (RCC_DMA1);
+
+ while (i2c_lock());
+
+ i2cp_bringup (I2C1);
+ i2cp_bringup (I2C2);
+
+ i2c_unlock();
+}