/* * (c) danielinux 2019 * GPLv.2 * * See LICENSE for details */ #include #include #include "system.h" #include "i2c.h" #include "display.h" #define DISPLAY_I2C_ADDR 0x3C #define I2C1 (0x40005400) #define APB1_SPEED_IN_MHZ (42) #define I2C1_CR1 (*(volatile uint32_t *)(I2C1)) #define I2C1_CR2 (*(volatile uint32_t *)(I2C1 + 0x04)) #define I2C1_OAR1 (*(volatile uint32_t *)(I2C1 + 0x08)) #define I2C1_OAR2 (*(volatile uint32_t *)(I2C1 + 0x0c)) #define I2C1_DR (*(volatile uint32_t *)(I2C1 + 0x10)) #define I2C1_SR1 (*(volatile uint32_t *)(I2C1 + 0x14)) #define I2C1_SR2 (*(volatile uint32_t *)(I2C1 + 0x18)) #define I2C1_CCR (*(volatile uint32_t *)(I2C1 + 0x1c)) #define I2C1_TRISE (*(volatile uint32_t *)(I2C1 + 0x20)) #define I2C_CR1_ENABLE (1 << 0) #define I2C_CR1_START (1 << 8) #define I2C_CR1_STOP (1 << 9) #define I2C_CR1_ACK (1 << 10) #define I2C_CR2_FREQ_MASK (0x3ff) #define I2C_CCR_MASK (0xfff) #define I2C_TRISE_MASK (0x3f) #define I2C_SR1_START (1 << 0) #define I2C_SR1_TX_BTF (1 << 2) #define I2C_SR1_ADDR_SENT (1 << 1) #define I2C_SR1_RX_NOTEMPTY (1 << 6) #define I2C_SR1_TX_EMPTY (1 << 7) #define I2C_SR2_MASTER (1 << 0) #define I2C_SR2_BUSY (1 << 1) #define I2C_SR2_XMIT (1 << 2) #define APB1_CLOCK_ER (*(volatile uint32_t *)(0x40023840)) #define APB1_CLOCK_RST (*(volatile uint32_t *)(0x40023820)) #define I2C1_APB1_CLOCK_ER_VAL (1 << 21) static void i2c1_pins_setup(void) { uint32_t reg; AHB1_CLOCK_ER |= GPIOB_AHB1_CLOCK_ER; /* Set mode = AF */ reg = GPIOB_MODE & ~ (0x03 << (I2C1_SCL * 2)); GPIOB_MODE = reg | (2 << (I2C1_SCL * 2)); reg = GPIOB_MODE & ~ (0x03 << (I2C1_SDA * 2)); GPIOB_MODE = reg | (2 << (I2C1_SDA * 2)); /* Alternate function: */ reg = GPIOB_AFH & ~(0xf << ((I2C1_SCL - 8) * 4)); GPIOB_AFH = reg | (I2C1_PIN_AF << ((I2C1_SCL - 8) * 4)); reg = GPIOB_AFH & ~(0xf << ((I2C1_SDA - 8) * 4)); GPIOB_AFH = reg | (I2C1_PIN_AF << ((I2C1_SDA - 8) * 4)); } static void i2c1_reset(void) { APB1_CLOCK_RST |= I2C1_APB1_CLOCK_ER_VAL; APB1_CLOCK_RST &= ~I2C1_APB1_CLOCK_ER_VAL; } static void i2c1_send_start(void) { volatile uint32_t sr1; I2C1_CR1 |= I2C_CR1_START; do { sr1 = I2C1_SR1; } while ((sr1 & I2C_SR1_START) == 0);; } static void i2c1_send_stop(void) { I2C1_CR1 |= I2C_CR1_STOP; } void display_send_data(void *priv, const uint8_t *buf, int len) { volatile uint32_t sr1, sr2; int i; volatile uint8_t drval; uint32_t start_data = 0x00000040; uint8_t address = DISPLAY_I2C_ADDR; I2C1_CR1 &= ~I2C_CR1_ENABLE; I2C1_CR1 &= ~I2C_CR1_STOP; I2C1_CR1 &= ~I2C_CR1_ACK; I2C1_CR1 |= I2C_CR1_ENABLE; /* Wait if the bus is busy */ do { sr2 = I2C1_SR2; } while ((sr2 & I2C_SR2_BUSY) != 0);; /* Send a start condition */ i2c1_send_start(); /* Send address + R/W = 0 */ I2C1_DR = (address << 1); do { sr1 = I2C1_SR1; } while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT); do { sr2 = I2C1_SR2; } while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));; I2C1_DR = start_data; do { sr1 = I2C1_SR1; } while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0); for (i = 0; i < len; i++) { I2C1_DR = buf[i]; do { sr1 = I2C1_SR1; if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) { drval = I2C1_DR; } } while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0); } while ((sr1 & (I2C_SR1_TX_BTF)) == 0) { sr1 = I2C1_SR1; } i2c1_send_stop(); } int i2c1_send(uint8_t address, const uint8_t *buf, int len) { volatile uint32_t sr1, sr2; int i; volatile uint8_t drval; I2C1_CR1 &= ~I2C_CR1_ENABLE; I2C1_CR1 &= ~I2C_CR1_STOP; I2C1_CR1 &= ~I2C_CR1_ACK; I2C1_CR1 |= I2C_CR1_ENABLE; /* Wait if the bus is busy */ do { sr2 = I2C1_SR2; } while ((sr2 & I2C_SR2_BUSY) != 0);; /* Send a start condition */ i2c1_send_start(); /* Send address + R/W = 0 */ I2C1_DR = (address << 1); do { sr1 = I2C1_SR1; } while ((sr1 & I2C_SR1_ADDR_SENT) != I2C_SR1_ADDR_SENT); do { sr2 = I2C1_SR2; } while ((sr2 & (I2C_SR2_BUSY | I2C_SR2_MASTER)) != (I2C_SR2_BUSY | I2C_SR2_MASTER));; for (i = 0; i < len; i++) { I2C1_DR = buf[i]; do { sr1 = I2C1_SR1; if ((sr1 & I2C_SR1_RX_NOTEMPTY) == I2C_SR1_RX_NOTEMPTY) { drval = I2C1_DR; } } while ((sr1 & (I2C_SR1_TX_EMPTY)) == 0); } while ((sr1 & (I2C_SR1_TX_BTF)) == 0) { sr1 = I2C1_SR1; } i2c1_send_stop(); return i; } void i2c1_setup(void) { uint32_t reg; i2c1_pins_setup(); APB1_CLOCK_ER |= I2C1_APB1_CLOCK_ER_VAL; I2C1_CR1 &= ~I2C_CR1_ENABLE; i2c1_reset(); reg = I2C1_CR2 & ~(I2C_CR2_FREQ_MASK); I2C1_CR2 = reg | APB1_SPEED_IN_MHZ; reg = I2C1_CCR & ~(I2C_CCR_MASK); // I2C1_CCR = reg | (APB1_SPEED_IN_MHZ * 5); I2C1_CCR = reg | 35; reg = I2C1_TRISE & ~(I2C_TRISE_MASK); I2C1_TRISE = reg | (APB1_SPEED_IN_MHZ + 1); I2C1_CR1 |= I2C_CR1_ENABLE; } void i2c_display_init(void) { i2c1_setup(); display_init(NULL); } void display_send_cmd(void *priv, uint8_t cmd) { uint8_t buf[2] = {0x00, cmd}; volatile int j; i2c1_send(DISPLAY_I2C_ADDR, buf, 2); } void display_send_cmd1(void *priv, uint8_t cmd, uint8_t arg1) { uint8_t buf[3] = {0x00, cmd, arg1}; volatile int j; i2c1_send(DISPLAY_I2C_ADDR, buf, 3); } void display_send_cmd2(void *priv, uint8_t cmd, uint8_t arg1, uint8_t arg2) { uint8_t buf[4] = {0x00, cmd, arg1, arg2}; volatile int j; i2c1_send(DISPLAY_I2C_ADDR, buf, 3); }