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_ */