Hi,
I am using the Tiva C Series Connected Launchpad TM4C1924XL and currently I am writing a class for SPI.
I have defined some flags for the constructor for Slave mode, Polarity, Phase, the ability to write and read data. But I am not sure if it is possible to read from the SPI without configuring the MOSI pin. In the case of SSI2 I normally do something like this:
ROM_GPIOPinConfigure(GPIO_PD1_SSI2XDAT0); GPIOPinTypeSSI(GPIO_PORTD_BASE, GPIO_PIN_1);
Am I able to read data from SSI2 if MOSI is not configured liked this? What is if I want to use pin 1 on Port D for normal GPIO stuff? So I would only connect SCLK and MISO to the external device. Am I able to read data with SSIDataGet(SSI2_BASE, &value);?
Thank you!
This is the class so far.
SPI.h
#ifndef SPI_H_
#define SPI_H_
#include "helper/common.h"
#include <stdint.h>
#include "driverlib/ssi.h" // for SSI
#include "driverlib/gpio.h" // for GPIO_PIN_0 to GPIO_PIN_7
#include "driverlib/rom.h" // for all ROM_ functions
namespace SPIFlags {
enum Flags {
Writable = _BV(0),
Readable = _BV(1),
Slave = _BV(2),
Polarity = _BV(3),
Phase = _BV(4)
};
// 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));}
}
class SPI {
private:
static const uint32_t SSIPeriph[4];
static const uint32_t SSIBase[4];
static const uint32_t SSIGPIOPeriph[4];
// Reihenfolge: MISO, MOSI, SCLK
static const uint32_t SSIGPIOPins[4][3];
static const uint32_t SSIGPIOBase[4];
// Reihenfolge: MISO, MOSI, SCLK
static const uint32_t SSIGPIOType[4][3];
int spi;
uint32_t base; // für schnelleren Zugriff
public:
SPI(int spi, int frequency, SPIFlags::Flags flags) {
this->spi = spi;
base = SSIBase[spi];
ROM_IntMasterDisable();
// Aktiviere SSI- und GPIO-Peripherie
ROM_SysCtlPeripheralEnable(SSIPeriph[spi]);
ROM_SysCtlDelay(3);
ROM_SysCtlPeripheralEnable(SSIGPIOPeriph[spi]);
ROM_SysCtlDelay(3);
if (spi == 1) {
ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); //TODO nicht so schön
ROM_SysCtlDelay(3);
}
ROM_SSIDisable(base);
// Konfiguriere die Pins für SSI als MISO, MOSI und SCLK
// SCLK
ROM_GPIOPinConfigure(SSIGPIOPins[spi][2]);
if (spi == 1) {
GPIOPinTypeSSI(GPIO_PORTB_BASE, SSIGPIOType[spi][2]); //TODO nicht so schön
} else {
GPIOPinTypeSSI(SSIGPIOBase[spi], SSIGPIOType[spi][2]);
}
// MOSI
if (flags & SPIFlags::Writable) {
ROM_GPIOPinConfigure(SSIGPIOPins[spi][1]);
GPIOPinTypeSSI(SSIGPIOBase[spi], SSIGPIOType[spi][1]);
}
// MISO
if (flags & SPIFlags::Readable) {
ROM_GPIOPinConfigure(SSIGPIOPins[spi][0]);
GPIOPinTypeSSI(SSIGPIOBase[spi], SSIGPIOType[spi][0]);
}
ROM_SSIClockSourceSet(base, SSI_CLOCK_SYSTEM);
// Berechne SSI Mode
uint32_t ui32Mode;
if (flags & SPIFlags::Slave) {
if (not (flags & SPIFlags::Writable)) {
ui32Mode = SSI_MODE_SLAVE_OD;
} else {
ui32Mode = SSI_MODE_SLAVE;
}
} else {
ui32Mode = SSI_MODE_MASTER;
}
// Berechne SSI Protocol
uint32_t ui32Protocol;
if (flags & SPIFlags::Polarity) {
if (flags & SPIFlags::Phase) {
ui32Protocol = SSI_FRF_MOTO_MODE_3;
} else {
ui32Protocol = SSI_FRF_MOTO_MODE_2;
}
} else {
if (flags & SPIFlags::Phase) {
ui32Protocol = SSI_FRF_MOTO_MODE_1;
} else {
ui32Protocol = SSI_FRF_MOTO_MODE_0;
}
}
// Initialisiere SSI
ROM_SSIConfigSetExpClk(base, F_CPU, ui32Protocol, ui32Mode, frequency, 8);
// Aktiviere SSI
ROM_SSIEnable(base);
// Clear out any initial data that might be present in the RX FIFO
if (flags & SPIFlags::Readable) {
unsigned long initialData = 0;
while (ROM_SSIDataGetNonBlocking(base, (uint32_t*) &initialData));
}
ROM_IntMasterEnable();
}
virtual ~SPI() {
ROM_SSIDisable(base);
};
void send(uint8_t value) {
ROM_SSIDataPut(base, value);
}
void waitBusy() {
while (ROM_SSIBusy(base));
}
uint8_t receive() {
uint32_t value;
SSIDataGet(base, &value);
return value & 0xff;
}
};
#endif /* SPI_H_ */
SPI.cpp
#include <components/SPI.h>
const uint32_t SPI::SSIPeriph[4] = {
SYSCTL_PERIPH_SSI0, SYSCTL_PERIPH_SSI1, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3
};
const uint32_t SPI::SSIBase[4] = {
SSI0_BASE, SSI1_BASE, SSI2_BASE, SSI3_BASE
};
const uint32_t SPI::SSIGPIOPeriph[4] = {
SYSCTL_PERIPH_GPIOA, SYSCTL_PERIPH_GPIOB, SYSCTL_PERIPH_GPIOD, SYSCTL_PERIPH_GPIOF
};
// Reihenfolge: MISO, MOSI, SCLK
const uint32_t SPI::SSIGPIOPins[4][3] = {
{ GPIO_PA5_SSI0XDAT1, GPIO_PA4_SSI0XDAT0, GPIO_PA2_SSI0CLK },
{ GPIO_PE5_SSI1XDAT1, GPIO_PE4_SSI1XDAT0, GPIO_PB5_SSI1CLK }, /* FIXME Port E und B! Momentan gelöst durch if (spi == 1) */
{ GPIO_PD0_SSI2XDAT1, GPIO_PD1_SSI2XDAT0, GPIO_PD3_SSI2CLK },
{ GPIO_PF0_SSI3XDAT1, GPIO_PF1_SSI3XDAT0, GPIO_PF3_SSI3CLK}
};
const uint32_t SPI::SSIGPIOBase[4] = {
GPIO_PORTA_BASE, GPIO_PORTE_BASE, GPIO_PORTD_BASE, GPIO_PORTF_BASE
};
// Reihenfolge: MISO, MOSI, SCLK
const uint32_t SPI::SSIGPIOType[4][3] = {
{ GPIO_PIN_5, GPIO_PIN_4, GPIO_PIN_2 },
{ GPIO_PIN_5, GPIO_PIN_4, GPIO_PIN_5 },
{ GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_3 },
{ GPIO_PIN_0, GPIO_PIN_1, GPIO_PIN_3 }
};
helper/common.h
/* * common.h * * Created on: 10.12.2014 * Author: nicolas */ #ifndef COMMON_H_ #define COMMON_H_ #include <stdint.h> #include "driverlib/sysctl.h" #include "inc/hw_memmap.h" #include "driverlib/pin_map.h" extern uint32_t F_CPU; #define _BV(b) (1 << (b)) #endif /* COMMON_H_ */