This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Can I read vom SSI without enabling MOSI?

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

 

 

 

  • Hello Nicolas,

    Without configuring a Pin for the Peripheral function, the Data Read/Control would not work. It would return a default value in this case of 0x0. This is assuming what you meant was that the SSI is in Slave Mode and MOSI Pin is still GPIO. In that case the SSI peripheral will be getting 0 from the Pin Mux/Demux

    Regards
    Amit
  • Either I misunderstood you or you misunderstood me. :)
    Of course I would configure the pins SCLK and MISO for the SSI peripheral function. I just wouldn't configure MOSI as SSI pin. What happens if I use SSIDataPut and MOSI is configured as normal GPIO pin? Would the data be send to /dev/null and incoming data read into the MISO buffer? Or would just happen nothing or occur a undefined CPU state?
  • Hello Nicolas,

    If MOSI is not configured as SSI Pin, but as a GPIO Pin then, the output of the pin will be as decided by the GPIO DATA register, SSI would send data to nothing and MISO will still work and you would get data into the RXBUFFER

    Regards
    Amit