DrOldies

[Energia Library] Updated SPI lm4f library TM4C123 & TM4C1294

5 posts in this topic

(I started this [Energia Library] topic and copied my spiE library over to make it easier to find)

I wanted to improve the compatibility of the SPI.h lm4f library to include functions of arduino user contributed SPI.h libraries. I found SPI2.h here: http://forum.stellar...two-spi-modules. This library added multi-module features but removed the 123 & 1294 compatibility. I have merged SPI2 and the core SPI libs into spiE.h and added several more function variations. 

 

spiE.h best features are:

 

1. Array transfer up to 255 bytes. This is 5x faster than single byte transfer.

2. SPI2's pinMode() and digitalWrire() functions are replaced with faster macros.

3. Support for __TM4C129XNCZAD__, __TM4C1294NCPDT__, BLIZZARD_RB1 (LM4F) boards

4. Up to 4 instances can be defined: SPI0, SPI1, SPI3, & SPI2 is instantiated by default as SPI for arduino code compatibility.

5. Multiple SlaveSelect pins can be used fir multiple devices on one data line. defaultSS, default +SS2, or SS1 + SS2, etc.

 

I have tested this on the 129. If you have a need for it and can try it on the other boards before I upload it to github, be my guest.

spiE.zip

Share this post


Link to post
Share on other sites

As it happens I have been tinkering with the SPI library some (tinkering with the speed setting, which doesn't work well on Stellaris/Tiva), so here is some fairly detailed feedback.

(Some of this is general improvements to the SPI library, while others are specific to this version.)

 

The test for Tiva processors in the header file only works if Energia.h already included.
(Not every sketch includes Energia.h, see for instance SPI examples included with Energia,
like BarometricPressureSensor, which break if you have this test there. ).

#if defined(__TM4C129XNCZAD__) || defined(__TM4C1294NCPDT__) || defined(__LM4F120H5QR__) || defined(__TM4C123GH6PM__)

Why use SSIModule= NOT_ACTIVE in constructor?
(I know the original does, but it just seems to cause problems without any benefit.)

Makes constructor do some bad things.  Expanding the macro definitions it winds up as follows:
 

SPIClass::SPIClass(void) {
    SSIModule = 0xA;
    SSIBitOrder = MSBFIRST;
    _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(g_u8SlaveSelPins[0xA]));  
    _ssMask_ = digitalPinToBitMask(g_u8SlaveSelPins[0xA]);                 
} 

So we are reading some arbitrary memory location beyond the end of the pins array to fill _ssBase_, _ssMask_ with garbage.
Why?  (Good thing we don't have memory protection, or we could get slapped for that.)

Only reason I see to use NOT_ACTIVE would be if all the other functions checked for that SSIModule value, and
either fixed the error by calling begin, or signaled an error themselves.

Fix - set SSIModule to the default value when you start (unless given another value). (Just remove test from begin method.)

SPIClass::SPIClass(void) {
    SSIModule = BOOST_PACK_SPI;
    SSIBitOrder = MSBFIRST;
    _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(SSPIN));  
    _ssMask_ = digitalPinToBitMask(SSPIN);                 
}

Why change class constructor to take an unsigned long (rather than uint8_t)?

  SPIClass(unsigned long);  //spi3

It seems unlikely we will ever need more than 255 SPI modules.

Opens up greater range of errors (could pass it a much larger value and the compiler wouldn't warn us).  Also problematic since did not change setModule to take an unsigned long, and did not change module varible to be unsigned long.

 

 

end - should deselect the device (set slave select pin to not active)

    ROM_GPIOPinWrite(_ssBase_, _ssMask_, _ssMask_);

(e.g. if did a transfer saying there was more to come, and then called end, it would leave the device selected.).

The no argument version of end should use the correct pin value (just as the no argument version of begin does)
that way if argument to end starts to matter (as it would if fixed problem above), then it won't break things.

void SPIClass::end(void) {    //for SPI compatibility only
  end(SSPIN);
}

end with pin argument - should check that pin matches the pin that have been using, (or just remove the option of designating an ssPin for end)

 

 

in transfer - why is it testing for !ssPin?

    if (!ssPin || (!repeatFlag)) {
        _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(ssPin));
        _ssMask_ = digitalPinToBitMask(ssPin); 
    }

So if ssPin is 0 (i.e., !ssPin is true), then _ssBase_ will be set to portBASERegister(pintoport(0)) (Not a valid port)

If ssPin is not 0, then ssPin will be ignored (unless repeatFlag is false).

 

 

Why does multi-byte transfer just write (no read)?
  If want it to only write, suggest change the name to write (to leave the name "transfer" available for doing read/write).

Why multi-byte transfer limited to 255 characters?  (Might as well give it a 16 bit unsigned length, unless there is special reason).

(If going to just write, then make the buffer const, so I can write data direct from flash.)

 

 

setDataMode - should limit (mask) mode argument

void SPIClass::setDataMode(uint8_t mode) {
HWREG(SSIBASE + SSI_O_CR0) &= ~(SSI_CR0_SPO | SSI_CR0_SPH);
HWREG(SSIBASE + SSI_O_CR0) |= mode & (SSI_CR0_SPO | SSI_CR0_SPH);
}

setClockDivider - should limit divider to valid values

void SPIClass::setClockDivider(uint8_t divider){
  //value must be even
  HWREG(SSIBASE + SSI_O_CPSR) = ( divider & SSI_CPSR_CPSDVSR_M);
}

Need range checking on module argument to setModule and to class constructor

void SPIClass::setModule(uint8_t module) {
  // This would work in C, haven't found equivalent construct in C++, may have to just define NUM_SPI
  if (module < sizeof(g_ulSSIBase)/sizeof(g_ulSSIBase[0])) {
    SSIModule = module;
    begin();
  }
}

Other SPI module instances (SPI1, etc.) probably not a good idea, since any of them can be changed to any module with a setModule.  Increases probability of interference with other code, encourages use of crypic names, without clear benefit.
Also becomes pretty arbitrary (why define 4 of them when that is not the number of SPI modules)?
(Perhaps providing another instance of SPI for the default SPI for the second BP connector on the 1294 might make sense,
if could figure out a sensible way to use it.)

 

Stellarisiti - mis-spelled in comment
another typo - LM4C - either TM4C or LM4F

 

Consider move code for functions that just call other function to header file (saves a little time/code space).

 

Attached has revised version of spiE, with some of the above changes made.  (Tested to be sure compiles, but haven't tried running it.  Some of the range checks were from versions of the SPI code that I have been working on.)

spiE.zip

Share this post


Link to post
Share on other sites

As a followup/update to my previous post - NOT_ACTIVE - may be friendlier to use this to make sure that begin gets called at the appropriate time, even if the user forgets.  (Since Energia is targeted at nonprogrammers/beginners.)

 

Here is a modified version of spiE.cpp which should do that (again, not tested).

/* spiE.cpp
 * Copyright (c) 2010 by Cristian Maglie <c.maglie@bug.st>
 * SPI Master library for arduino.
 *
 * This file is free software; you can redistribute it and/or modify
 * it under the terms of either the GNU General Public License version 2
 * or the GNU Lesser General Public License version 2.1, both as
 * published by the Free Software Foundation.
 */


#include "wiring_private.h"
#include "inc/hw_memmap.h"
#include "inc/hw_ssi.h"
#include "inc/hw_types.h"
#include "driverlib/ssi.h"
#include "driverlib/gpio.h"
#include "driverlib/sysctl.h"
#include "driverlib/pin_map.h"
#include "part.h"

#include "spiE.h"

#define SSIBASE g_ulSSIBase[SSIModule]
#define SSPIN g_u8SlaveSelPins[SSIModule] 
#define NOT_ACTIVE 0x4F

/* variants
   stellarpad - LM4F120H5QR, TM4C123GH6PM, aka TARGET_IS_BLIZZARD_RB1
    i base  port
    0 SSI0 PA
    1 SSI1 PF
    2 SSI2 PB
    3 SSI3 PD

   dktm4c129 - TM4C129XNCZAD 
    i base  port
    0 SSI0  PA
    1 SSI1  PB/PE
    2 SSI2  PD
    3 SSI3  PF 
    4 SSI2  PG 
    5 SSI3  PQ

   ektm4c12944XL - TM4C1294NCPDT (TIVA C)
    i base  port
    0 SSI0  PA
    1 SSI1  PB/PE
    2 SSI2  PD
    3 SSI3  PF 
    4 SSI3  PQ
*/

static const unsigned long g_ulSSIBase[] = {
#ifdef TARGET_IS_BLIZZARD_RB1
    SSI0_BASE, SSI1_BASE, SSI2_BASE, SSI3_BASE
#else
#ifdef __TM4C129XNCZAD__
    SSI0_BASE, SSI1_BASE, SSI2_BASE, SSI3_BASE, SSI2_BASE, SSI3_BASE
#endif
#ifdef __TM4C1294NCPDT__
    SSI0_BASE, SSI1_BASE, SSI2_BASE, SSI3_BASE, SSI3_BASE
#endif
#endif
};

//*****************************************************************************
//
// The list of SSI peripherals.
//
//*****************************************************************************
static const unsigned long g_ulSSIPeriph[] = {
#ifdef TARGET_IS_BLIZZARD_RB1
    SYSCTL_PERIPH_SSI0, SYSCTL_PERIPH_SSI1, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3
#else
#ifdef __TM4C129XNCZAD__
    SYSCTL_PERIPH_SSI0, SYSCTL_PERIPH_SSI1, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3
#endif
#ifdef __TM4C1294NCPDT__
    SYSCTL_PERIPH_SSI0, SYSCTL_PERIPH_SSI1, SYSCTL_PERIPH_SSI2, SYSCTL_PERIPH_SSI3, SYSCTL_PERIPH_SSI3
#endif
#endif

};

//*****************************************************************************
//
// The list of SSI gpio configurations.
//
//*****************************************************************************
static const unsigned long g_ulSSIConfig[][4] = {
#ifdef TARGET_IS_BLIZZARD_RB1
    {GPIO_PA2_SSI0CLK, GPIO_PA3_SSI0FSS, GPIO_PA4_SSI0RX, GPIO_PA5_SSI0TX},
    {GPIO_PF2_SSI1CLK, GPIO_PF3_SSI1FSS, GPIO_PF0_SSI1RX, GPIO_PF1_SSI1TX},
    {GPIO_PB4_SSI2CLK, GPIO_PB5_SSI2FSS, GPIO_PB6_SSI2RX, GPIO_PB7_SSI2TX},
    {GPIO_PD0_SSI3CLK, GPIO_PD1_SSI3FSS, GPIO_PD2_SSI3RX, GPIO_PD3_SSI3TX}
#else
#ifdef __TM4C129XNCZAD__
// from Table 20-1. SSI Signals (212BGA)
    {GPIO_PA2_SSI0CLK, GPIO_PA3_SSI0FSS, GPIO_PA4_SSI0XDAT0, GPIO_PA5_SSI0XDAT1},
    {GPIO_PB5_SSI1CLK, GPIO_PB4_SSI1FSS, GPIO_PE4_SSI1XDAT0, GPIO_PE5_SSI1XDAT1},
    {GPIO_PD3_SSI2CLK, GPIO_PD2_SSI2FSS, GPIO_PD1_SSI2XDAT0, GPIO_PD0_SSI2XDAT1},
    {GPIO_PF3_SSI3CLK, GPIO_PF2_SSI3FSS, GPIO_PF1_SSI3XDAT0, GPIO_PF0_SSI3XDAT1},
    {GPIO_PG7_SSI2CLK, GPIO_PG6_SSI2FSS, GPIO_PG5_SSI2XDAT0, GPIO_PG4_SSI2XDAT1},
    {GPIO_PQ0_SSI3CLK, GPIO_PQ1_SSI3FSS, GPIO_PQ2_SSI3XDAT0, GPIO_PQ3_SSI3XDAT1}
#endif
#ifdef __TM4C1294NCPDT__
// from Table 17-1. SSI Signals (128TQFP)
    {GPIO_PA2_SSI0CLK, GPIO_PA3_SSI0FSS, GPIO_PA4_SSI0XDAT0, GPIO_PA5_SSI0XDAT1},
    {GPIO_PB5_SSI1CLK, GPIO_PB4_SSI1FSS, GPIO_PE4_SSI1XDAT0, GPIO_PE5_SSI1XDAT1},
    {GPIO_PD3_SSI2CLK, GPIO_PD2_SSI2FSS, GPIO_PD1_SSI2XDAT0, GPIO_PD0_SSI2XDAT1},
    {GPIO_PF3_SSI3CLK, GPIO_PF2_SSI3FSS, GPIO_PF1_SSI3XDAT0, GPIO_PF0_SSI3XDAT1},
    {GPIO_PQ0_SSI3CLK, GPIO_PQ1_SSI3FSS, GPIO_PQ2_SSI3XDAT0, GPIO_PQ3_SSI3XDAT1}
#endif
#endif
,};

//*****************************************************************************
//
// The list of SSI gpio port bases.
//
//*****************************************************************************
static const unsigned long g_ulSSIPort[] = {
#ifdef TARGET_IS_BLIZZARD_RB1
    GPIO_PORTA_BASE, GPIO_PORTF_BASE, GPIO_PORTB_BASE, GPIO_PORTD_BASE
#else
#ifdef __TM4C129XNCZAD__
    GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTD_BASE, GPIO_PORTF_BASE, GPIO_PORTG_BASE, GPIO_PORTQ_BASE
#endif
#ifdef __TM4C1294NCPDT__
    GPIO_PORTA_BASE, GPIO_PORTB_BASE, GPIO_PORTD_BASE, GPIO_PORTF_BASE, GPIO_PORTQ_BASE
#endif
#endif
};

//*****************************************************************************
//
// The list of SSI gpio configurations.
//
//*****************************************************************************
static const unsigned long g_ulSSIPins[] = {
#ifdef TARGET_IS_BLIZZARD_RB1
	GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5,
	GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3,
	GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7,
	GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
#else
#ifdef __TM4C129XNCZAD__
	GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5,
	GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_4 | GPIO_PIN_5,
	GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0,
	GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0,
	GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4,
	GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
#endif
#ifdef __TM4C1294NCPDT__
	GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5,
	GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_4 | GPIO_PIN_5,
	GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0,
	GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0,
	GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3
#endif
#endif
};

//*****************************************************************************
//
// The list of SlaveSelect Default Pins.    entire section spi3
//
//*****************************************************************************
static const uint8_t g_u8SlaveSelPins[] = {
#ifdef TARGET_IS_BLIZZARD_RB1
  PA_3, PF_3, PB_5, PD_1
#else
#ifdef __TM4C129XNCZAD__
  PA_3, PB_4, PD_2, PF_2
#endif
#ifdef __TM4C1294NCPDT__
   PA_3, PB_4, PD_2, PF_2, PQ_1
#endif
#endif
};


SPIClass::SPIClass(void) {
	SSIModule = NOT_ACTIVE;
	SSIBitOrder = MSBFIRST;

    //slaveSelect = SSPIN;
//    _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(SSPIN));   
//    _ssMask_ = digitalPinToBitMask(SSPIN);                  
}

SPIClass::SPIClass(uint8_t module) {   
	SSIModule = module;
	SSIBitOrder = MSBFIRST;
	//slaveSelect = SSPIN;        
    _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(SSPIN));   
    _ssMask_ = digitalPinToBitMask(SSPIN); 
}
  
void SPIClass::begin(uint8_t ssPin) {
	unsigned long initialData = 0;

    if(SSIModule == NOT_ACTIVE) {
        SSIModule = BOOST_PACK_SPI;
		_ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(SSPIN));   
		_ssMask_ = digitalPinToBitMask(SSPIN);  		
    }

	ROM_SysCtlPeripheralEnable(g_ulSSIPeriph[SSIModule]);
	ROM_SSIDisable(SSIBASE);
	ROM_GPIOPinConfigure(g_ulSSIConfig[SSIModule][0]);
	ROM_GPIOPinConfigure(g_ulSSIConfig[SSIModule][1]);
	ROM_GPIOPinConfigure(g_ulSSIConfig[SSIModule][2]);
	ROM_GPIOPinConfigure(g_ulSSIConfig[SSIModule][3]);
#ifdef TARGET_IS_BLIZZARD_RB1
	ROM_GPIOPinTypeSSI(g_ulSSIPort[SSIModule], g_ulSSIPins[SSIModule]);
#else
#if defined(__TM4C129XNCZAD__) || defined(__TM4C1294NCPDT__)
    if (SSIModule == 1) { // 1 is a split port 
	    ROM_GPIOPinTypeSSI(GPIO_PORTB_BASE, GPIO_PIN_5 | GPIO_PIN_4);
	    ROM_GPIOPinTypeSSI(GPIO_PORTE_BASE, GPIO_PIN_4 | GPIO_PIN_5);
    } else {
	    ROM_GPIOPinTypeSSI(g_ulSSIPort[SSIModule], g_ulSSIPins[SSIModule]);
    }
#endif
#endif
	/*
	  Polarity Phase        Mode
	     0 	   0   SSI_FRF_MOTO_MODE_0
	     0     1   SSI_FRF_MOTO_MODE_1
	     1     0   SSI_FRF_MOTO_MODE_2
	     1     1   SSI_FRF_MOTO_MODE_3
	*/
	
    //slaveSelect = ssPin;                
     _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(ssPin));   
    _ssMask_ =  digitalPinToBitMask(ssPin);   
	//pinMode(slaveSelect, OUTPUT); 
    ROM_GPIOPinTypeGPIOOutput(_ssBase_, _ssMask_);

	/*
	 * Default to
	 * System Clock, SPI_MODE_0, MASTER,
	 * 4MHz bit rate, and 8 bit data
	*/
	ROM_SSIClockSourceSet(SSIBASE, SSI_CLOCK_SYSTEM);

#ifdef TARGET_IS_BLIZZARD_RB1
	ROM_SSIConfigSetExpClk(SSIBASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8);
#else
	ROM_SSIConfigSetExpClk(SSIBASE, F_CPU, SSI_FRF_MOTO_MODE_0, SSI_MODE_MASTER, 8000000, 8);
#endif

	ROM_SSIEnable(SSIBASE);

	//clear out any initial data that might be present in the RX FIFO
	while(ROM_SSIDataGetNonBlocking(SSIBASE, &initialData));
}
//spi3 replaces original
void SPIClass::begin() {
    if(SSIModule == NOT_ACTIVE) {
        begin(g_u8SlaveSelPins[BOOST_PACK_SPI]);
    }
	else
		begin(SSPIN);
}

//spi3 simulates both usual spi versions
void SPIClass::end(uint8_t ssPin) {     //for SPI compatibility only
    if(SSIModule != NOT_ACTIVE) {
		ROM_GPIOPinWrite(_ssBase_, _ssMask_, _ssMask_);
		ROM_SSIDisable(SSIBASE);
	}
}

void SPIClass::end(void) {    //for SPI compatibility only
    if(SSIModule != NOT_ACTIVE) {
		end(SSPIN);
	}
}

void SPIClass::setBitOrder(uint8_t ssPin, uint8_t bitOrder) {
	SSIBitOrder = bitOrder;
}

void SPIClass::setBitOrder(uint8_t bitOrder) {
	SSIBitOrder = bitOrder;
}

void SPIClass::setDataMode(uint8_t mode) {
    if(SSIModule == NOT_ACTIVE) 
		begin();
	HWREG(SSIBASE + SSI_O_CR0) &= ~(SSI_CR0_SPO | SSI_CR0_SPH);
	HWREG(SSIBASE + SSI_O_CR0) |= mode & (SSI_CR0_SPO | SSI_CR0_SPH);
}

void SPIClass::setClockDivider(uint8_t divider){
    if(SSIModule == NOT_ACTIVE) 
		begin();
	//value must be even
	HWREG(SSIBASE + SSI_O_CPSR) = ( divider & SSI_CPSR_CPSDVSR_M);
}

//spi3 new version
uint8_t SPIClass::transfer(uint8_t ssPin, uint8_t data, uint8_t transferMode) {
	static uint8_t repeatFlag = false;         //are we CONTUNUEing a string?
    unsigned long rxtxData;
    if(SSIModule == NOT_ACTIVE) 
		begin(ssPin);

	//digitalWrite(ssPin, LOW);
    //spi3a - pin=0 means use current
    //getting base and mask every time is much slower
    if (!ssPin || (!repeatFlag)) {
        _ssBase_ = (uint32_t) portBASERegister(digitalPinToPort(ssPin)); 
        _ssMask_ = digitalPinToBitMask(ssPin);  
    }
    ROM_GPIOPinWrite(_ssBase_, _ssMask_, 0); 

	rxtxData = data;
	if(SSIBitOrder == LSBFIRST) {
		asm("rbit %0, %1" : "=r" (rxtxData) : "r" (rxtxData));	// reverse order of 32 bits 
		asm("rev %0, %1" : "=r" (rxtxData) : "r" (rxtxData));	// reverse order of bytes to get original bits into lowest byte 
	}
	ROM_SSIDataPut(SSIBASE, (uint8_t) rxtxData);
    
	if(transferMode == SPI_LAST){ 
		//digitalWrite(ssPin, HIGH);
            ROM_GPIOPinWrite(_ssBase_, _ssMask_, _ssMask_); 
            repeatFlag = false;
        }
	else  {                                    //SPI_CONTUNUE
	   //digitalWrite(ssPin, LOW);
           //ROM_GPIOPinWrite(_ssBase_, ssMask_, 0);    // already low ???
            repeatFlag = true;                  //s we are in CONTIUNE transfer mode
        }
	while(ROM_SSIBusy(SSIBASE));

	ROM_SSIDataGet(SSIBASE, &rxtxData);
	if(SSIBitOrder == LSBFIRST) {
		asm("rbit %0, %1" : "=r" (rxtxData) : "r" (rxtxData));	// reverse order of 32 bits 
		asm("rev %0, %1" : "=r" (rxtxData) : "r" (rxtxData));	// reverse order of bytes to get original bits into lowest byte 
	}

	return (uint8_t) rxtxData;
}

//byte array to 255 bytes
void SPIClass::transfer(const uint8_t *dataString, uint8_t numBytes) {
    unsigned long rxtxData;
    if(SSIModule == NOT_ACTIVE) 
		begin();

    //use currently active pin
    ROM_GPIOPinWrite(_ssBase_, _ssMask_, 0);     //low

    for(unsigned char i = numBytes; i > 0 ; i--){ 
        rxtxData = dataString[i - 1];
        if(SSIBitOrder == LSBFIRST) {
            asm("rbit %0, %1" : "=r" (rxtxData) : "r" (rxtxData));  // reverse order of 32 bits 
            asm("rev %0, %1" : "=r" (rxtxData) : "r" (rxtxData));   // reverse order of bytes to get original bits into lowest byte 
        }
        ROM_SSIDataPut(SSIBASE, (uint8_t) rxtxData);
        while(ROM_SSIBusy(SSIBASE));            //avoid buffer overflow
     }
    ROM_GPIOPinWrite(_ssBase_, _ssMask_, _ssMask_); //high
}

void SPIClass::setModule(uint8_t module) {
	SSIModule = module;
	begin();
}

//Convert from one SPI instantiation of SPI to 4 modules: 
//SPI0, SPI1, SPI (for backwards compatibility), and SPI3 
//SPI is the default for previous SPI libraries and for 
//TIVA C: SPI BUS 2 -> BOOST_PACK_SPI
SPIClass SPI0(0);
SPIClass SPI1(1);
SPIClass SPI(2);   // default as "SPI" 
SPIClass SPI3(3);

Share this post


Link to post
Share on other sites

hello People !! I have traying to upload this code (see below) in Tiva C LP with CC2530 AIR MODULE. I have this errors, someone gives me some help please. " I have libreries in order and all"

Issues:

C:\Users\Myriam\Documents\Energia\libraries\SPI\SPI.cpp: In member function 'void SPIClass::begin()':
C:\Users\Myriam\Documents\Energia\libraries\SPI\SPI.cpp:207:55: error: invalid conversion from 'long unsigned int*' to 'uint32_t* {aka unsigned int*}' [-fpermissive]
  while(ROM_SSIDataGetNonBlocking(SSIBASE, &initialData));
                                                       ^
C:\Users\Myriam\Documents\Energia\libraries\SPI\SPI.cpp: In member function 'uint8_t SPIClass::transfer(uint8_t)':
C:\Users\Myriam\Documents\Energia\libraries\SPI\SPI.cpp:244:35: error: invalid conversion from 'long unsigned int*' to 'uint32_t* {aka unsigned int*}' [-fpermissive]
  ROM_SSIDataGet(SSIBASE, &rxtxData);

Tiva_measurment.ino

Share this post


Link to post
Share on other sites

Hi.  A while back I had the need to send two bytes of data to a digital potentiometer without changing the state of chip select pin between the two bytes.  I ended up modifying the SPI library and calling it altSPI.  Essentially, the only change was to add two defined things called trans2ByteA and trans2ByteB.  The first of these selects the chip and transmits the first Byte.  The second transmits the second byte and then de-selects the chip.   These are defined in altSPI.cpp as in the code below.  The library can be found at https://github.com/SmokyMountainScientific/altSPI. 

If I were to do this again I would define a third function that transfers a byte without changing the CS state at all.

uint8_t altSPIClass::trans2ByteA(uint8_t data) {

  return transfer(slaveSelect, data, SPI_CONTINUE);

}
uint8_t altSPIClass::trans2ByteB(uint8_t data) {

  return transfer(slaveSelect, data, SPI_LAST);

}

 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now