You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
277 lines
4.1 KiB
277 lines
4.1 KiB
#include <stdlib.h>
|
|
#include "stm32f4xx.h"
|
|
#include "gpio.h"
|
|
#include "i2c.h"
|
|
#include "dwt.h"
|
|
|
|
struct i2c {
|
|
GPIO_TypeDef *scl_port;
|
|
uint32_t scl;
|
|
|
|
GPIO_TypeDef *sda_port;
|
|
uint32_t sda;
|
|
|
|
unsigned int ticks;
|
|
};
|
|
|
|
#define DELAY_TICKS (4)
|
|
|
|
extern GPIO_TypeDef *gpio_port(uint32_t pin);
|
|
|
|
#define SCL_H(i2c) (((i2c)->scl_port)->BSRRL) = (((i2c)->scl) & PIN_MASK)
|
|
#define SCL_L(i2c) (((i2c)->scl_port)->BSRRH) = (((i2c)->scl) & PIN_MASK)
|
|
#define SDA_H(i2c) (((i2c)->sda_port)->BSRRL) = (((i2c)->sda) & PIN_MASK)
|
|
#define SDA_L(i2c) (((i2c)->sda_port)->BSRRH) = (((i2c)->sda) & PIN_MASK)
|
|
#define SCL_IN(i2c) ((((i2c)->scl_port)-IDR) & (((i2c)->sda) & PIN_MASK))
|
|
#define SDA_IN(i2c) ((((i2c)->sda_port)->IDR) & (((i2c)->sda) & PIN_MASK))
|
|
|
|
i2c_t i2c_new(uint32_t scl, uint32_t sda, int speed)
|
|
{
|
|
i2c_t i2c = malloc(sizeof *i2c);
|
|
if (i2c == NULL) {
|
|
return NULL;
|
|
}
|
|
i2c->scl = scl;
|
|
i2c->scl_port = gpio_port(scl);
|
|
i2c->sda = sda;
|
|
i2c->sda_port = gpio_port(sda);
|
|
|
|
gpio_init(i2c->scl, GPIO_OUTPUT | GPIO_FLAG_PU | GPIO_FLAG_OD | GPIO_SPEED_LOW);
|
|
gpio_init(i2c->sda, GPIO_OUTPUT | GPIO_FLAG_PU | GPIO_FLAG_OD | GPIO_SPEED_LOW);
|
|
|
|
SCL_H(i2c);
|
|
SDA_H(i2c);
|
|
|
|
if (speed > 0) {
|
|
i2c->ticks = 4000000 / speed / 2;
|
|
} else {
|
|
i2c->ticks = DELAY_TICKS;
|
|
}
|
|
|
|
return (i2c);
|
|
}
|
|
|
|
void i2c_free(i2c_t i2c)
|
|
{
|
|
free(i2c);
|
|
}
|
|
|
|
int i2c_start(i2c_t i2c)
|
|
{
|
|
int en, err = 0;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SDA_H(i2c);
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
if (!SDA_IN(i2c)) { /* sda busy ? */
|
|
err = -1;
|
|
goto err;
|
|
}
|
|
|
|
SDA_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
if (SDA_IN(i2c)) { /* sda hi, error. */
|
|
err = -2;
|
|
goto err;
|
|
}
|
|
|
|
SDA_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
err:
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
void i2c_stop(i2c_t i2c)
|
|
{
|
|
int en;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SDA_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SDA_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
}
|
|
|
|
void i2c_ack(i2c_t i2c)
|
|
{
|
|
int en;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SDA_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
}
|
|
|
|
void i2c_nack(i2c_t i2c)
|
|
{
|
|
int en;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SDA_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
}
|
|
|
|
int i2c_wait_ack(i2c_t i2c)
|
|
{
|
|
int en, err;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SDA_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
err = SDA_IN(i2c);
|
|
|
|
SCL_L(i2c);
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
|
|
return err;
|
|
}
|
|
|
|
int i2c_send_byte(i2c_t i2c, uint8_t byte)
|
|
{
|
|
int en, i = 8;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
while(i--) {
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
if(byte & 0x80)
|
|
SDA_H(i2c);
|
|
else
|
|
SDA_L(i2c);
|
|
|
|
byte <<= 1;
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
}
|
|
SCL_L(i2c);
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
uint8_t i2c_recv_byte(i2c_t i2c)
|
|
{
|
|
int en, i = 8;
|
|
uint8_t rd = 0;
|
|
|
|
if (!(en = dwt_is_enabled())) {
|
|
dwt_init();
|
|
}
|
|
|
|
SDA_H(i2c);
|
|
|
|
while(i--) {
|
|
rd <<= 1;
|
|
|
|
SCL_L(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
SCL_H(i2c);
|
|
|
|
dwt_wait_us(i2c->ticks);
|
|
|
|
if (SDA_IN(i2c)) {
|
|
rd |= 0x01;
|
|
}
|
|
}
|
|
SCL_L(i2c);
|
|
if (!en) {
|
|
dwt_close();
|
|
}
|
|
return (rd);
|
|
}
|
|
|
|
|