ssd1306 i2c .c - JohnHau/mis GitHub Wiki
/**
- original author: Tilen Majerle[email protected]
-
[email protected]
modification for STM32f10x: Alexander Lutsaihttp://www.gnu.org/licenses/.
Copyright (C) Alexander Lutsai, 2016 Copyright (C) Tilen Majerle, 2015 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see
*/ #include "ssd1306_i2c.h"
/* Private variables */ static uint32_t ssd1306_I2C_Timeout;
/* Private defines */ #define I2C_TRANSMITTER_MODE 0 #define I2C_RECEIVER_MODE 1 #define I2C_ACK_ENABLE 1 #define I2C_ACK_DISABLE 0
void ssd1306_I2C_Init() { GPIO_InitTypeDef gpio; I2C_InitTypeDef i2c;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
i2c.I2C_ClockSpeed = 400000;
i2c.I2C_Mode = I2C_Mode_I2C;
i2c.I2C_DutyCycle = I2C_DutyCycle_2;
i2c.I2C_OwnAddress1 = 0x15;
i2c.I2C_Ack = I2C_Ack_Disable;
i2c.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
I2C_Init(I2C1, &i2c);
gpio.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
gpio.GPIO_Mode = GPIO_Mode_AF_OD;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &gpio);
// Íó è âêëþ÷àåì, ñîáñòâåííî, ìîäóëü I2C1
I2C_Cmd(I2C1, ENABLE);
}
void ssd1306_I2C_WriteMulti(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t* data, uint16_t count) { uint8_t i; ssd1306_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE); ssd1306_I2C_WriteData(I2Cx, reg); for (i = 0; i < count; i++) { ssd1306_I2C_WriteData(I2Cx, data[i]); } ssd1306_I2C_Stop(I2Cx); }
/* Private functions / int16_t ssd1306_I2C_Start(I2C_TypeDef I2Cx, uint8_t address, uint8_t direction, uint8_t ack) { /* Generate I2C start pulse */ I2Cx->CR1 |= I2C_CR1_START;
/* Wait till I2C is busy */
ssd1306_I2C_Timeout = ssd1306_I2C_TIMEOUT;
while (!(I2Cx->SR1 & I2C_SR1_SB)) {
if (--ssd1306_I2C_Timeout == 0x00) {
return 1;
}
}
/* Enable ack if we select it */
if (ack) {
I2Cx->CR1 |= I2C_CR1_ACK;
}
/* Send write/read bit */
if (direction == I2C_TRANSMITTER_MODE) {
/* Send address with zero last bit */
I2Cx->DR = address & ~I2C_OAR1_ADD0;
/* Wait till finished */
ssd1306_I2C_Timeout = ssd1306_I2C_TIMEOUT;
while (!(I2Cx->SR1 & I2C_SR1_ADDR)) {
if (--ssd1306_I2C_Timeout == 0x00) {
return 1;
}
}
}
if (direction == I2C_RECEIVER_MODE) {
/* Send address with 1 last bit */
I2Cx->DR = address | I2C_OAR1_ADD0;
/* Wait till finished */
ssd1306_I2C_Timeout = ssd1306_I2C_TIMEOUT;
while (!I2C_CheckEvent(I2Cx, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) {
if (--ssd1306_I2C_Timeout == 0x00) {
return 1;
}
}
}
/* Read status register to clear ADDR flag */
I2Cx->SR2;
/* Return 0, everything ok */
return 0;
}
void ssd1306_I2C_WriteData(I2C_TypeDef* I2Cx, uint8_t data) { /* Wait till I2C is not busy anymore */ ssd1306_I2C_Timeout = ssd1306_I2C_TIMEOUT; while (!(I2Cx->SR1 & I2C_SR1_TXE) && ssd1306_I2C_Timeout) { ssd1306_I2C_Timeout--; }
/* Send I2C data */
I2Cx->DR = data;
}
void ssd1306_I2C_Write(I2C_TypeDef* I2Cx, uint8_t address, uint8_t reg, uint8_t data) { ssd1306_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_DISABLE); ssd1306_I2C_WriteData(I2Cx, reg); ssd1306_I2C_WriteData(I2Cx, data); ssd1306_I2C_Stop(I2Cx); }
uint8_t ssd1306_I2C_Stop(I2C_TypeDef* I2Cx) { /* Wait till transmitter not empty */ ssd1306_I2C_Timeout = ssd1306_I2C_TIMEOUT; while (((!(I2Cx->SR1 & I2C_SR1_TXE)) || (!(I2Cx->SR1 & I2C_SR1_BTF)))) { if (--ssd1306_I2C_Timeout == 0x00) { return 1; } }
/* Generate stop */
I2Cx->CR1 |= I2C_CR1_STOP;
/* Return 0, everything ok */
return 0;
}
uint8_t ssd1306_I2C_IsDeviceConnected(I2C_TypeDef* I2Cx, uint8_t address) { uint8_t connected = 0; /* Try to start, function will return 0 in case device will send ACK */ if (!ssd1306_I2C_Start(I2Cx, address, I2C_TRANSMITTER_MODE, I2C_ACK_ENABLE)) { connected = 1; }
/* STOP I2C */
ssd1306_I2C_Stop(I2Cx);
/* Return status */
return connected;
}