From b3df20a08974584076e802d5f7061a8a8cb96930 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 16 Jul 2015 08:35:16 +0100 Subject: initial commit --- app/i2c.c | 281 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 281 insertions(+) create mode 100644 app/i2c.c (limited to 'app/i2c.c') diff --git a/app/i2c.c b/app/i2c.c new file mode 100644 index 0000000..74aed9d --- /dev/null +++ b/app/i2c.c @@ -0,0 +1,281 @@ +#include "project.h" + + +#define I2C I2C1 + +#define SCL GPIO6 +#define SDA GPIO7 + +void +i2c_clear_start (uint32_t i2c) +{ + I2C_CR1 (i2c) &= ~(uint32_t) I2C_CR1_START; +} + +#if 0 +static void +i2cp_ds (void) +{ + uint32_t i2c = I2C; + printf ("CR1=%08x CR2=%08x\r\n", (unsigned) I2C_CR1 (i2c), + (unsigned) I2C_CR2 (i2c)); + printf ("SR1=%08x SR2=%08x\r\n", (unsigned) I2C_SR1 (i2c), + (unsigned) I2C_SR2 (i2c)); + + + usart1_drain (); +} +#endif + + + +void +i2cp_start (void) +{ + i2c_send_start (I2C); + while (!((I2C_SR1 (I2C) & I2C_SR1_SB) + & (I2C_SR2 (I2C) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); +} + +void +i2cp_abort_start (void) +{ + i2c_clear_start (I2C); + delay_us (10); +} + +void +i2cp_stop (void) +{ + i2c_send_stop (I2C); +} + + +void +i2cp_abort_stop (void) +{ + i2c_clear_stop (I2C); + delay_us (10); +} + +int +i2cp_send_data (uint8_t v) +{ + uint32_t reg; + + 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))); + I2C_SR1 (I2C) = + reg & ~(I2C_SR1_BERR | I2C_SR1_ARLO | I2C_SR1_AF | I2C_SR1_PECERR | + I2C_SR1_TIMEOUT | I2C_SR1_SMBALERT); + + + return (reg & I2C_SR1_BTF) ? 0 : -1; +} + +/*0 on success 1 on failure*/ +int +i2cp_start_transaction (uint8_t a, int wnr) +{ + uint32_t reg; + uint32_t __attribute__ ((unused)) dummy; + + i2c_send_start (I2C); + while (!((I2C_SR1 (I2C) & I2C_SR1_SB) + & (I2C_SR2 (I2C) & (I2C_SR2_MSL | I2C_SR2_BUSY)))); + + 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))); + 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; +} + + +static int mutex = 0; + +int +i2cp_lock (void) +{ + if (__sync_add_and_fetch (&mutex, 1) != 1) + { + __sync_sub_and_fetch (&mutex, 1); + return -1; + } + + return 0; +} + + +void +i2cp_unlock (void) +{ + __sync_sub_and_fetch (&mutex, 1); +} + + /*This is stupid, it bit bangs a dummy transaction to get the host i2c controller back in the game */ +static void +i2cp_reset_sm (void) +{ + int i; + + gpio_set_mode (GPIOB, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_PUSHPULL, GPIO_I2C1_SCL | GPIO_I2C1_SDA); + + gpio_set (GPIOB, GPIO_I2C1_SDA); + gpio_set (GPIOB, GPIO_I2C1_SCL); + delay_us (10); + gpio_clear (GPIOB, GPIO_I2C1_SDA); + delay_us (10); + gpio_clear (GPIOB, GPIO_I2C1_SCL); + + for (i = 0; i < 9; ++i) + { + delay_us (10); + gpio_set (GPIOB, GPIO_I2C1_SCL); + delay_us (10); + gpio_clear (GPIOB, GPIO_I2C1_SCL); + delay_us (10); + } + gpio_set (GPIOB, GPIO_I2C1_SCL); + delay_us (10); + gpio_set (GPIOB, GPIO_I2C1_SDA); + delay_us (10); + +} + +void +i2cp_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); + +} + +int +i2cp_dma_in_progress (void) +{ + return !(DMA1_ISR & (DMA_ISR_TCIF6 | DMA_ISR_TEIF6)); +} + +void +i2cp_stop_dma (void) +{ + DMA1_IFCR |= DMA_IFCR_CTCIF7 | 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_CHANNEL7); +} + +void +i2cp_reset (void) +{ + while (i2cp_lock ()); + i2cp_start (); + i2cp_abort_start (); + i2cp_stop (); + i2cp_abort_stop (); + + i2cp_start (); + i2cp_abort_start (); + i2cp_stop (); + i2cp_abort_stop (); + i2cp_unlock (); +} + + + +void +i2cp_scan (void) +{ + int i, r; + + return; + i2cp_reset (); + + printf ("Probing bus\r\n"); + for (i = 0; i < 128; ++i) + { + while (i2cp_lock ()); + i2cp_start (); + i2cp_abort_start (); + i2cp_stop (); + i2cp_abort_stop (); + r = i2cp_start_transaction (i, I2C_WRITE); + i2cp_stop (); + i2cp_unlock (); + if (!r) + printf ("Found device at address 0x%x\r\n", i); + usart1_drain (); + } + printf ("Done\r\n"); + i2cp_reset (); + +} + +void +i2cp_init (void) +{ + rcc_periph_clock_enable (RCC_I2C1); + rcc_periph_clock_enable (RCC_DMA1); + + while (i2cp_lock ()); + + + 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; + + + i2cp_reset_sm (); + + gpio_set_mode (GPIOB, GPIO_MODE_OUTPUT_50_MHZ, + GPIO_CNF_OUTPUT_ALTFN_OPENDRAIN, + GPIO_I2C1_SCL | GPIO_I2C1_SDA); + + i2c_set_clock_frequency (I2C, I2C_CR2_FREQ_36MHZ); + i2c_set_standard_mode (I2C); + i2c_set_ccr (I2C, 0x200); /* t_high=t_high=CCR * Tpclk1 */ + i2c_set_trise (I2C, 0x0b); + + i2c_set_own_7bit_slave_address (I2C, 0x00); + + i2c_peripheral_enable (I2C); + i2cp_unlock (); +} -- cgit v1.2.3