microscope-ring-light-remot.../i2c.c

138 lines
2.5 KiB
C

#include "stm32f030x6.h"
#include <i2c.h>
#include <stdint.h>
void i2c_init(void)
{
RCC->APB1ENR |= RCC_APB1ENR_I2C1EN;
/* Use SYSCLK for I2C, because HSI (default) is disabled */
RCC->CFGR3 |= RCC_CFGR3_I2C1SW;
i2c_reset();
/* Setup clocks */
I2C1->TIMINGR = ((6 << 28) & I2C_TIMINGR_PRESC) | ((8 << 20) & I2C_TIMINGR_SCLDEL) |
((8 << 16) & I2C_TIMINGR_SDADEL) | ((0x20 << 8) & I2C_TIMINGR_SCLH) |
((0x20 << 0) & I2C_TIMINGR_SCLL);
/* Peripheral enable */
I2C1->CR1 = I2C_CR1_PE;
}
int i2c_write(uint8_t i2c_addr, const uint8_t *data, uint8_t len)
{
uint32_t isr;
/* Clear stop flag */
I2C1->ICR |= I2C_ICR_STOPCF;
/* Setup len bytes for write transfer */
I2C1->CR2 = I2C_CR2_AUTOEND | ((len << 16 ) & I2C_CR2_NBYTES) | (i2c_addr & 0xFE) | I2C_CR2_START;
do {
isr = I2C1->ISR;
if (isr & I2C_ISR_NACKF) {
/* NACK received */
return -1;
} else if (isr & I2C_ISR_TXIS) {
/* I2C ready to get data to send */
I2C1->TXDR = (uint32_t)*data;
data++;
len--;
}
} while (len > 0);
/* All data transferred. Wait for automatically generated stop */
while (!(I2C1->ISR & I2C_ISR_STOPF)) {
if (I2C1->ISR & I2C_ISR_NACKF) {
return -1;
}
}
/* Clear stop flag */
I2C1->ICR |= I2C_ICR_STOPCF;
return 0;
}
int i2c_read(uint8_t i2c_addr, uint8_t command, uint8_t *data, uint8_t len)
{
int run;
int err;
uint32_t isr;
if (!data || !len) {
return -1000;
}
/* Clear stop flag */
I2C1->ICR |= I2C_ICR_STOPCF;
/* Setup len bytes for write transfer of command */
I2C1->CR2 = ((1 << 16 ) & I2C_CR2_NBYTES) | (i2c_addr & 0xFE) | I2C_CR2_START;
err = 0;
run = 1;
do {
isr = I2C1->ISR;
if (isr & I2C_ISR_NACKF) {
err = 1;
run = 0;
} else if (isr & I2C_ISR_TXIS) {
I2C1->TXDR = (uint32_t)command;
run = 0;
}
} while (run);
if (err) {
return -1;
}
/* Wait for command to be transmitted */
run = 1;
err = 0;
do {
isr = I2C1->ISR;
if (isr & I2C_ISR_NACKF) {
err = 1;
run = 0;
} else if (isr & I2C_ISR_TC) {
run = 0;
}
} while (run);
if (err) {
return -1;
}
/* Setup read request */
I2C1->CR2 = I2C_CR2_AUTOEND | I2C_CR2_RD_WRN | ((len << 16 ) & I2C_CR2_NBYTES) | (i2c_addr & 0xFE) | I2C_CR2_START;
while (len) {
if (I2C1->ISR & I2C_ISR_RXNE) {
*data = I2C1->RXDR;
data++;
len--;
}
}
while (!(I2C1->ISR & I2C_ISR_STOPF)) {
if (I2C1->ISR & I2C_ISR_NACKF) {
return -1;
}
}
/* Clear stop flag */
I2C1->ICR |= I2C_ICR_STOPCF;
return 0;
}
void i2c_reset(void)
{
I2C1->CR1 = 0;
I2C1->CR2 = 0;
}