Hi there,
I am using the Tiva C Series Connected Launchpad TM4C1294XL and I just wrote a class for commuticating over I2C. Can you please tell me if the methods are correct? I am not sure about the methode sendReceiveBuffer. I don't know when I have to call the I2CMasterControl function for switching from sending to receiving.
/*
* I2C.h
*
* Created on: 16.04.2015
* Author: nicolas
*/
#ifndef I2C_H_
#define I2C_H_
#include "helper/common.h"
#include <stdint.h>
#include "driverlib/i2c.h" // for SSI
#include "driverlib/gpio.h" // for GPIO_PIN_0 to GPIO_PIN_7
#include "driverlib/rom.h" // for all ROM_ functions
#include "driverlib/pin_map.h"
#include "inc/hw_memmap.h"
namespace I2CFlags {
enum Flags {
Fast = _BV(0)
};
// Notwendig, damit man Flags mit dem | Operator verodern/verknüpfen kann.
inline Flags operator|(Flags a, Flags b)
{return static_cast<Flags>(static_cast<int>(a) | static_cast<int>(b));}
}
namespace I2CPorts {
static const uint32_t I2CPeriph[14] = {
SYSCTL_PERIPH_I2C0, SYSCTL_PERIPH_I2C1, SYSCTL_PERIPH_I2C2, SYSCTL_PERIPH_I2C2, SYSCTL_PERIPH_I2C3,
SYSCTL_PERIPH_I2C4, SYSCTL_PERIPH_I2C5, SYSCTL_PERIPH_I2C5, SYSCTL_PERIPH_I2C6, SYSCTL_PERIPH_I2C7,
SYSCTL_PERIPH_I2C7, SYSCTL_PERIPH_I2C8, SYSCTL_PERIPH_I2C8, SYSCTL_PERIPH_I2C9
};
static const uint32_t I2CBase[14] = {
I2C0_BASE, I2C1_BASE, I2C2_BASE, I2C2_BASE, I2C3_BASE,
I2C4_BASE, I2C5_BASE, I2C5_BASE, I2C6_BASE, I2C7_BASE,
I2C7_BASE, I2C8_BASE, I2C8_BASE, I2C9_BASE
};
static const uint32_t I2CGPIOPeriph[14] = {
SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOG, SYSCTL_PERIPH_GPIOL, SYSCTL_PERIPH_GPION, SYSCTL_PERIPH_GPIOK,
SYSCTL_PERIPH_GPIOK, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOD,
SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOD, SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOA
};
// Reihenfolge: SCL, SDA
static const uint32_t I2CGPIOPins[14][2] = {
{ GPIO_PB2_I2C0SCL, GPIO_PB3_I2C0SDA },
{ GPIO_PG0_I2C1SCL, GPIO_PG1_I2C1SDA },
{ GPIO_PL1_I2C2SCL, GPIO_PL0_I2C2SDA },
{ GPIO_PN5_I2C2SCL, GPIO_PN4_I2C2SDA },
{ GPIO_PK4_I2C3SCL, GPIO_PK5_I2C3SDA },
{ GPIO_PK6_I2C4SCL, GPIO_PK7_I2C4SDA },
{ GPIO_PB0_I2C5SCL, GPIO_PB1_I2C5SDA },
{ GPIO_PB4_I2C5SCL, GPIO_PB5_I2C5SDA },
{ GPIO_PA6_I2C6SCL, GPIO_PA7_I2C6SDA },
{ GPIO_PD0_I2C7SCL, GPIO_PD1_I2C7SDA },
{ GPIO_PA4_I2C7SCL, GPIO_PA5_I2C7SDA },
{ GPIO_PD2_I2C8SCL, GPIO_PD3_I2C8SDA },
{ GPIO_PA2_I2C8SCL, GPIO_PA3_I2C8SDA },
{ GPIO_PA0_I2C9SCL, GPIO_PA1_I2C9SDA },
};
static const uint32_t I2CGPIOBase[14] = {
GPIO_PORTB_BASE, GPIO_PORTG_BASE, GPIO_PORTL_BASE, GPIO_PORTN_BASE, GPIO_PORTK_BASE,
GPIO_PORTK_BASE, GPIO_PORTB_BASE, GPIO_PORTB_BASE, GPIO_PORTA_BASE, GPIO_PORTD_BASE,
GPIO_PORTA_BASE, GPIO_PORTD_BASE, GPIO_PORTA_BASE, GPIO_PORTA_BASE
};
// Reihenfolge: SCL, SDA
static const uint32_t I2CGPIOType[14][2] = {
{ GPIO_PIN_2, GPIO_PIN_3 },
{ GPIO_PIN_0, GPIO_PIN_1 },
{ GPIO_PIN_1, GPIO_PIN_0 },
{ GPIO_PIN_5, GPIO_PIN_4 },
{ GPIO_PIN_4, GPIO_PIN_6 },
{ GPIO_PIN_6, GPIO_PIN_7 },
{ GPIO_PIN_0, GPIO_PIN_1 },
{ GPIO_PIN_4, GPIO_PIN_5 },
{ GPIO_PIN_6, GPIO_PIN_7 },
{ GPIO_PIN_0, GPIO_PIN_1 },
{ GPIO_PIN_4, GPIO_PIN_5 },
{ GPIO_PIN_2, GPIO_PIN_3 },
{ GPIO_PIN_2, GPIO_PIN_3 },
{ GPIO_PIN_0, GPIO_PIN_1 }
};
}
class I2C {
protected:
int i2c;
uint32_t base; // für schnelleren Zugriff
public:
I2C(int i2c, I2CFlags::Flags flags) {
this->i2c = i2c;
base = I2CPorts::I2CBase[i2c];
ROM_IntMasterDisable();
// Aktiviere I2C- und GPIO-Peripherie
ROM_SysCtlPeripheralEnable(I2CPorts::I2CPeriph[i2c]);
ROM_SysCtlDelay(3);
ROM_SysCtlPeripheralReset(I2CPorts::I2CPeriph[i2c]);
ROM_SysCtlPeripheralEnable(I2CPorts::I2CGPIOPeriph[i2c]);
ROM_SysCtlDelay(3);
// Deaktiviere I2C Master und Slave Block
I2CMasterDisable(base); //FIXME: Wahrscheinlich nicht nötig wegen dem Reset oben
I2CSlaveDisable(base);
// Konfiguriere die Pins für I2C als SCL und SDA
ROM_GPIOPinConfigure(I2CPorts::I2CGPIOPins[i2c][0]);
ROM_GPIOPinTypeI2CSCL(I2CPorts::I2CGPIOBase[i2c], I2CPorts::I2CGPIOType[i2c][0]);
ROM_GPIOPinConfigure(I2CPorts::I2CGPIOPins[i2c][1]);
ROM_GPIOPinTypeI2C(I2CPorts::I2CGPIOBase[i2c], I2CPorts::I2CGPIOType[i2c][1]);
//ROM_I2CClockSourceSet(base, SSI_CLOCK_SYSTEM); // Gibt's nicht. I2C nutzt immer die System Clock
bool bFast = false;
if (flags & I2CFlags::Fast) {
bFast = true;
}
ROM_I2CMasterInitExpClk(base, F_CPU, bFast);
// Aktiviere SSI
ROM_I2CMasterEnable(base);
ROM_IntMasterEnable();
};
~I2C() {
ROM_SysCtlPeripheralReset(I2CPorts::I2CPeriph[i2c]);
};
//FIXME: Add Error Handlers
int inline sendSingle(uint8_t value, uint8_t address) {
I2CMasterSlaveAddrSet(base, address, false);
ROM_I2CMasterDataPut(base, value);
while (ROM_I2CMasterBusBusy(base));
ROM_I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_SEND);
while(ROM_I2CMasterBusy(base));
//error?
return 0;
}
/**
* @return 0 successful.
*/
//FIXME: Add Error Handlers
int sendBuffer(uint8_t address, uint8_t* buffer, int length) {
ROM_I2CMasterSlaveAddrSet(base, address, false);
ROM_I2CMasterDataPut(base, *buffer++);
while (ROM_I2CMasterBusBusy(base));
if (length == 1) {
ROM_I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_SEND);
while(ROM_I2CMasterBusy(base));
//error?
return 0;
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_START);
length--;
while (true) {
while(ROM_I2CMasterBusy(base));
//error?
ROM_I2CMasterDataPut(base, *buffer++);
if (--length == 0) {
break;
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_CONT);
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_FINISH);
while(ROM_I2CMasterBusy(base));
//error?
return 0;
}
//FIXME: Add Error Handlers
uint8_t inline receiveSingle(uint8_t address) {
ROM_I2CMasterSlaveAddrSet(base, address, true);
while (ROM_I2CMasterBusBusy(base));
ROM_I2CMasterControl(base, I2C_MASTER_CMD_SINGLE_RECEIVE);
while(ROM_I2CMasterBusy(base));
//error?
uint32_t value;
value = ROM_I2CMasterDataGet(base);
return value & 0xff;
}
//FIXME: Add Error Handlers
int receiveBuffer(uint8_t address, uint8_t* buffer, int length) {
if (length == 1) {
*buffer = receiveSingle(address);
return 0;
}
ROM_I2CMasterSlaveAddrSet(base, address, true);
while (ROM_I2CMasterBusBusy(base));
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_START);
while (true) {
while(ROM_I2CMasterBusy(base));
//error?
*buffer++ = ROM_I2CMasterDataGet(base) & 0xff;
if (--length) {
break;
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
while(ROM_I2CMasterBusy(base));
//error?
*buffer = ROM_I2CMasterDataGet(base) & 0xff;
return 0;
}
//FIXME: Add Error Handlers
int sendReceiveBuffer(uint8_t address, uint8_t* sendBuffer, int sendLength, uint8_t* receiveBuffer, int receiveLength) {
ROM_I2CMasterSlaveAddrSet(base, address, false);
ROM_I2CMasterDataPut(base, *sendBuffer++);
while (ROM_I2CMasterBusBusy(base));
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_START);
sendLength--;
while (true) {
while(ROM_I2CMasterBusy(base));
//error?
if (--sendLength == 0) {
break;
}
ROM_I2CMasterDataPut(base, *sendBuffer++);
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_SEND_CONT);
}
ROM_I2CMasterSlaveAddrSet(base, address, true);
I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_START);
while (true) {
while(ROM_I2CMasterBusy(base));
//error?
*receiveBuffer++ = ROM_I2CMasterDataGet(base) & 0xff;
if (--receiveLength) {
break;
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_CONT);
}
ROM_I2CMasterControl(base, I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
while(ROM_I2CMasterBusy(base));
//error?
*receiveBuffer = ROM_I2CMasterDataGet(base) & 0xff;
return 0;
}
};
#endif /* I2C_H_ */
Thank you!