mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
Adapted to comments
This commit is contained in:
parent
7bab826c38
commit
fe15574c6b
@ -144,12 +144,9 @@ extern "C" {
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name I2C configuration
|
||||
* @{
|
||||
* @brief I2C configuration
|
||||
*/
|
||||
#define I2C_NUMOF 1
|
||||
#define I2C_0_EN 1
|
||||
#define I2C_IRQ_PRIO 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -105,12 +105,9 @@ extern "C" {
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name I2C configuration
|
||||
* @{
|
||||
* @brief I2C configuration
|
||||
*/
|
||||
#define I2C_NUMOF 1
|
||||
#define I2C_0_EN 1
|
||||
#define I2C_IRQ_PRIO 1
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -42,6 +42,15 @@ enum {
|
||||
PORT_G = 6, /**< port G */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name Defines for the I2C interface
|
||||
* @{
|
||||
*/
|
||||
#define I2C_PORT_REG PORTD
|
||||
#define I2C_PIN_MASK (1 << PORTD0) | (1 << PORTD1)
|
||||
#define I2C_POWER_REG PRR0
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -44,6 +44,15 @@ enum {
|
||||
PORT_L = 10 /**< port L */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name Defines for the I2C interface
|
||||
* @{
|
||||
*/
|
||||
#define I2C_PORT_REG PORTD
|
||||
#define I2C_PIN_MASK (1 << PORTD0) | (1 << PORTD1)
|
||||
#define I2C_POWER_REG PRR0
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -41,6 +41,15 @@ enum {
|
||||
PORT_D = 3 /**< port D */
|
||||
};
|
||||
|
||||
/**
|
||||
* @name Defines for the I2C interface
|
||||
* @{
|
||||
*/
|
||||
#define I2C_PORT_REG PORTC
|
||||
#define I2C_PIN_MASK (1 << PORTC4) | (1 << PORTC5)
|
||||
#define I2C_POWER_REG PRR
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -7,13 +7,14 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* @addtogroup driver_periph
|
||||
* @ingroup cpu_atmega_common
|
||||
* @ingroup drivers_periph_i2c
|
||||
* @{
|
||||
*
|
||||
* @file
|
||||
* @brief Low-level I2C driver implementation fot atmega common
|
||||
*
|
||||
* @note This implementation only implements the 7-bit addressing mode.
|
||||
* @note This implementation only implements the 7-bit addressing mode.
|
||||
*
|
||||
* @author Dimitri Nahm <dimitri.nahm@haw-hamburg.de>
|
||||
*
|
||||
@ -24,38 +25,35 @@
|
||||
|
||||
#include "cpu.h"
|
||||
#include "mutex.h"
|
||||
#include "assert.h"
|
||||
#include "periph/i2c.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#define ENABLE_DEBUG (0)
|
||||
#include "debug.h"
|
||||
|
||||
#define MT_START 0x08
|
||||
#define MT_ADDRESS_ACK 0x18
|
||||
#define MT_DATA_ACK 0x28
|
||||
#define MR_ADDRESS_ACK 0x40
|
||||
#define ENABLE_DEBUG (0)
|
||||
|
||||
/* guard file in case no I2C device is defined */
|
||||
#if I2C_NUMOF
|
||||
|
||||
#define MT_START 0x08
|
||||
#define MT_START_REPEATED 0x10
|
||||
#define MT_ADDRESS_ACK 0x18
|
||||
#define MT_DATA_ACK 0x28
|
||||
#define MR_ADDRESS_ACK 0x40
|
||||
|
||||
/* static function definitions */
|
||||
static int _start(uint8_t address, uint8_t rw_flag);
|
||||
static int _write(const uint8_t *data, int length);
|
||||
static void _stop(void);
|
||||
|
||||
/**
|
||||
* @brief Array holding one pre-initialized mutex for each I2C device
|
||||
*/
|
||||
static mutex_t locks[] = {
|
||||
#if I2C_0_EN
|
||||
[I2C_0] = MUTEX_INIT,
|
||||
#endif
|
||||
};
|
||||
static mutex_t lock = MUTEX_INIT;
|
||||
|
||||
int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
{
|
||||
/* TWI Bit Rate Register - division factor for the bit rate generator*/
|
||||
int twibrr;
|
||||
/* TWI Bit Rate Register - division factor for the bit rate generator */
|
||||
uint8_t twibrr;
|
||||
/* TWI Prescaler Bits - default 0 */
|
||||
uint8_t twipb = 0;
|
||||
|
||||
/* check if the line is valid */
|
||||
if (dev >= I2C_NUMOF) {
|
||||
@ -64,25 +62,49 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
|
||||
/* calculate speed configuration */
|
||||
switch (speed) {
|
||||
|
||||
case I2C_SPEED_LOW:
|
||||
if (CLOCK_CORECLOCK > 20000000U || CLOCK_CORECLOCK < 1000000U) {
|
||||
return -2;
|
||||
}
|
||||
twibrr = ((CLOCK_CORECLOCK/10000)-16)/(2*4); // CLK Prescaler 4
|
||||
twipb = 1;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_NORMAL:
|
||||
if (CLOCK_CORECLOCK > 50000000U || CLOCK_CORECLOCK < 2000000U) {
|
||||
return -2;
|
||||
}
|
||||
twibrr = ((CLOCK_CORECLOCK/100000)-16)/2;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_FAST:
|
||||
if (CLOCK_CORECLOCK < 7500000U) {
|
||||
return -2;
|
||||
}
|
||||
twibrr = ((CLOCK_CORECLOCK/400000)-16)/2;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_FAST_PLUS:
|
||||
if (CLOCK_CORECLOCK < 18000000U) {
|
||||
return -2;
|
||||
}
|
||||
twibrr = ((CLOCK_CORECLOCK/1000000)-16)/2;
|
||||
break;
|
||||
|
||||
case I2C_SPEED_HIGH:
|
||||
if (CLOCK_CORECLOCK < 62000000U) {
|
||||
return -2;
|
||||
}
|
||||
twibrr = ((CLOCK_CORECLOCK/3400000)-16)/2;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -2;
|
||||
}
|
||||
|
||||
/* set pull-up on SCL and SDA */
|
||||
#if defined (CPU_ATMEGA2560) || defined (CPU_ATMEGA1281)
|
||||
PORTD |= (1 << PORTD0) | (1 << PORTD1);
|
||||
#endif
|
||||
#ifdef CPU_ATMEGA328P
|
||||
PORTC |= (1 << PORTC4) | (1 << PORTC5);
|
||||
#endif
|
||||
I2C_PORT_REG |= (I2C_PIN_MASK);
|
||||
|
||||
/* enable I2C clock */
|
||||
i2c_poweron(dev);
|
||||
@ -90,7 +112,9 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
/* disable device */
|
||||
TWCR &= ~(1 << TWEN);
|
||||
/* configure I2C clock */
|
||||
TWBR = twibrr;
|
||||
TWBR = twibrr; // Set TWI Bit Rate Register
|
||||
TWSR &= ~(0x03); // Reset TWI Prescaler Bits
|
||||
TWSR |= twipb; // Set TWI Prescaler Bits
|
||||
/* enable device */
|
||||
TWCR |= (1 << TWEN);
|
||||
|
||||
@ -99,19 +123,15 @@ int i2c_init_master(i2c_t dev, i2c_speed_t speed)
|
||||
|
||||
int i2c_acquire(i2c_t dev)
|
||||
{
|
||||
if (dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_lock(&locks[dev]);
|
||||
assert(dev < I2C_NUMOF);
|
||||
mutex_lock(&lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i2c_release(i2c_t dev)
|
||||
{
|
||||
if (dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
mutex_unlock(&locks[dev]);
|
||||
assert(dev < I2C_NUMOF);
|
||||
mutex_unlock(&lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -124,24 +144,24 @@ int i2c_read_bytes(i2c_t dev, uint8_t address, void *data, int length)
|
||||
{
|
||||
uint8_t *my_data = data;
|
||||
|
||||
if ((unsigned int)dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
assert((dev < I2C_NUMOF) && (length > 0));
|
||||
|
||||
/* send start condition and slave address */
|
||||
if (_start(address, I2C_FLAG_READ) != 0)
|
||||
if (_start(address, I2C_FLAG_READ) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < length; i++) {
|
||||
/* Send NACK for last received byte */
|
||||
if ((length-i) == 1)
|
||||
if ((length - i) == 1) {
|
||||
TWCR = (1 << TWEN) | (1 << TWINT);
|
||||
else
|
||||
}
|
||||
else {
|
||||
TWCR = (1 << TWEA) | (1 << TWEN) | (1 << TWINT);
|
||||
}
|
||||
DEBUG("Wait for byte %i\n", i+1);
|
||||
/* Wait for TWINT Flag set. This indicates that DATA has been received.*/
|
||||
while (!(TWCR & (1 << TWINT)))
|
||||
{}
|
||||
while (!(TWCR & (1 << TWINT))) {}
|
||||
/* receive data byte */
|
||||
my_data[i] = TWDR;
|
||||
DEBUG("Byte %i received\n", i+1);
|
||||
@ -160,13 +180,12 @@ int i2c_read_reg(i2c_t dev, uint8_t address, uint8_t reg, void *data)
|
||||
|
||||
int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int length)
|
||||
{
|
||||
if ((unsigned int)dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
assert((dev < I2C_NUMOF) && (length > 0));
|
||||
|
||||
/* start transmission and send slave address */
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0)
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send register address and wait for complete transfer to be finished*/
|
||||
if (_write(®, 1) != 1) {
|
||||
@ -174,8 +193,6 @@ int i2c_read_regs(i2c_t dev, uint8_t address, uint8_t reg, void *data, int lengt
|
||||
return 0;
|
||||
}
|
||||
|
||||
_stop();
|
||||
|
||||
/* now start a new start condition and receive data */
|
||||
return i2c_read_bytes(dev, address, data, length);
|
||||
}
|
||||
@ -189,13 +206,12 @@ int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length)
|
||||
{
|
||||
int bytes = 0;
|
||||
|
||||
if ((unsigned int)dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
assert((dev < I2C_NUMOF) && (length > 0));
|
||||
|
||||
/* start transmission and send slave address */
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0)
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* send out data bytes */
|
||||
bytes = _write(data, length);
|
||||
@ -208,10 +224,6 @@ int i2c_write_bytes(i2c_t dev, uint8_t address, const void *data, int length)
|
||||
|
||||
int i2c_write_reg(i2c_t dev, uint8_t address, uint8_t reg, uint8_t data)
|
||||
{
|
||||
if ((unsigned int)dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return i2c_write_regs(dev, address, reg, &data, 1);
|
||||
}
|
||||
|
||||
@ -219,17 +231,17 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, in
|
||||
{
|
||||
int bytes = 0;
|
||||
|
||||
if ((unsigned int)dev >= I2C_NUMOF) {
|
||||
return -1;
|
||||
}
|
||||
assert((dev < I2C_NUMOF) && (length > 0));
|
||||
|
||||
/* start transmission and send slave address */
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0)
|
||||
if (_start(address, I2C_FLAG_WRITE) != 0) {
|
||||
return 0;
|
||||
}
|
||||
/* send register address and wait for complete transfer to be finished*/
|
||||
if (_write(®, 1))
|
||||
if (_write(®, 1)) {
|
||||
/* write data to register */
|
||||
bytes = _write(data, length);
|
||||
}
|
||||
/* finish transfer */
|
||||
_stop();
|
||||
/* return number of bytes send */
|
||||
@ -238,26 +250,14 @@ int i2c_write_regs(i2c_t dev, uint8_t address, uint8_t reg, const void *data, in
|
||||
|
||||
void i2c_poweron(i2c_t dev)
|
||||
{
|
||||
if (dev < I2C_NUMOF) {
|
||||
#if defined (CPU_ATMEGA2560) || defined (CPU_ATMEGA1281)
|
||||
PRR0 &= ~(1 << PRTWI);
|
||||
#endif
|
||||
#ifdef CPU_ATMEGA328P
|
||||
PRR &= ~(1 << PRTWI);
|
||||
#endif
|
||||
}
|
||||
assert(dev < I2C_NUMOF);
|
||||
I2C_POWER_REG &= ~(1 << PRTWI);
|
||||
}
|
||||
|
||||
void i2c_poweroff(i2c_t dev)
|
||||
{
|
||||
if (dev < I2C_NUMOF) {
|
||||
#if defined (CPU_ATMEGA2560) || defined (CPU_ATMEGA1281)
|
||||
PRR0 |= (1 << PRTWI);
|
||||
#endif
|
||||
#ifdef CPU_ATMEGA328P
|
||||
PRR |= (1 << PRTWI);
|
||||
#endif
|
||||
}
|
||||
assert(dev < I2C_NUMOF);
|
||||
I2C_POWER_REG |= (1 << PRTWI);
|
||||
}
|
||||
|
||||
static int _start(uint8_t address, uint8_t rw_flag)
|
||||
@ -267,36 +267,41 @@ static int _start(uint8_t address, uint8_t rw_flag)
|
||||
DEBUG("START condition transmitted\n");
|
||||
|
||||
/* Wait for TWINT Flag set. This indicates that the START has been
|
||||
transmitted, and ACK/NACK has been received.*/
|
||||
while (!(TWCR & (1 << TWINT)))
|
||||
{}
|
||||
* transmitted, and ACK/NACK has been received.*/
|
||||
while (!(TWCR & (1 << TWINT))) {}
|
||||
|
||||
/* Check value of TWI Status Register. Mask prescaler bits.
|
||||
If status different from START go to ERROR */
|
||||
if ((TWSR & 0xF8) != MT_START) {
|
||||
DEBUG("I2C Status Register is different from START\n");
|
||||
* If status different from START go to ERROR */
|
||||
if ((TWSR & 0xF8) == MT_START) {
|
||||
DEBUG("I2C Status is: START\n");
|
||||
}
|
||||
else if ((TWSR & 0xF8) == MT_START_REPEATED) {
|
||||
DEBUG("I2C Status is: START REPEATED\n");
|
||||
}
|
||||
else {
|
||||
DEBUG("I2C Status Register is different from START/START_REPEATED\n");
|
||||
_stop();
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
DEBUG("I2C Status Register is: START\n");
|
||||
|
||||
|
||||
/* Load ADDRESS and R/W Flag into TWDR Register.
|
||||
Clear TWINT bit in TWCR to start transmission of ADDRESS */
|
||||
* Clear TWINT bit in TWCR to start transmission of ADDRESS */
|
||||
TWDR = (address << 1) | rw_flag;
|
||||
TWCR = (1 << TWINT) | (1 << TWEN);
|
||||
DEBUG("ADDRESS and FLAG transmitted\n");
|
||||
|
||||
/* Wait for TWINT Flag set. This indicates that ADDRESS has been transmitted.*/
|
||||
while (!(TWCR & (1 << TWINT)))
|
||||
{}
|
||||
while (!(TWCR & (1 << TWINT))) {}
|
||||
|
||||
/* Check value of TWI Status Register. Mask prescaler bits.
|
||||
If status different from ADDRESS ACK go to ERROR */
|
||||
if ((TWSR & 0xF8) == MT_ADDRESS_ACK)
|
||||
* If status different from ADDRESS ACK go to ERROR */
|
||||
if ((TWSR & 0xF8) == MT_ADDRESS_ACK) {
|
||||
DEBUG("ACK has been received for ADDRESS (write)\n");
|
||||
else if ((TWSR & 0xF8) == MR_ADDRESS_ACK)
|
||||
}
|
||||
else if ((TWSR & 0xF8) == MR_ADDRESS_ACK) {
|
||||
DEBUG("ACK has been received for ADDRESS (read)\n");
|
||||
}
|
||||
else {
|
||||
DEBUG("NOT ACK has been received for ADDRESS\n");
|
||||
_stop();
|
||||
@ -308,38 +313,36 @@ static int _start(uint8_t address, uint8_t rw_flag)
|
||||
|
||||
static int _write(const uint8_t *data, int length)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < length; i++) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
/* Load DATA into TWDR Register.
|
||||
Clear TWINT bit in TWCR to start transmission of data */
|
||||
* Clear TWINT bit in TWCR to start transmission of data */
|
||||
TWDR = data[i];
|
||||
TWCR = (1 << TWINT) | (1 << TWEN);
|
||||
DEBUG("Byte %i transmitted\n", i+1);
|
||||
|
||||
/* Wait for TWINT Flag set. This indicates that DATA has been transmitted.*/
|
||||
while (!(TWCR & (1 << TWINT)))
|
||||
{}
|
||||
while (!(TWCR & (1 << TWINT))) {}
|
||||
|
||||
/* Check value of TWI Status Register. Mask prescaler bits. If status
|
||||
different from MT_DATA_ACK, return number of transmitted bytes */
|
||||
* different from MT_DATA_ACK, return number of transmitted bytes */
|
||||
if ((TWSR & 0xF8) != MT_DATA_ACK) {
|
||||
DEBUG("NACK has been received for BYTE %i\n", i+1);
|
||||
return i;
|
||||
}
|
||||
else
|
||||
else {
|
||||
DEBUG("ACK has been received for BYTE %i\n", i+1);
|
||||
}
|
||||
}
|
||||
|
||||
return i;
|
||||
return length;
|
||||
}
|
||||
|
||||
static void _stop(void)
|
||||
{
|
||||
/* Reset I2C Interrupt Flag and transmit STOP condition */
|
||||
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
|
||||
while (TWCR & (1 << TWSTO))
|
||||
{}
|
||||
/* Wait for STOP Flag reset. This indicates that STOP has been transmitted.*/
|
||||
while (TWCR & (1 << TWSTO)) {}
|
||||
DEBUG("STOP condition transmitted\n");
|
||||
TWCR = 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user