#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(); }