References versus Pointers: with class objects...

KurtE

Senior Member+
Sorry to all of you who have learned c++ a few decades after I did ;) Where maybe the answer is obvious.

I am in the process of trying to have all of the SPI objects to all be instances of one class, more up in the thread: https://forum.pjrc.com/threads/43048-How-best-to-manage-multiple-SPI-busses

I believe it is pretty much working, but then I decided to build one of the Teensyview examples which uses the Audio library and I received compile errors.
Code:
[Build] C:/Users/kurte/Documents/Arduino/libraries/SparkFun_TeensyView_Arduino_Library/examples/TeensyViewAudio...
[Step 1] Check Toolchain.
[Step 2] Find all source files.
[Step 3] Start building.
[0.8%] Compiling TeensyViewAudio.ino.cpp...
C:/Users/kurte/Documents/Arduino/libraries/SparkFun_TeensyView_Arduino_Library/examples/TeensyViewAudio/TeensyViewAudio.ino: In function 'void loop()':
C:/Users/kurte/Documents/Arduino/libraries/SparkFun_TeensyView_Arduino_Library/examples/TeensyViewAudio/TeensyViewAudio.ino:140:28: warning: 'loopTime' may be used uninitialized in this function [-Wmaybe-uninitialized]
     lastLoopTime = loopTime;
                            ^
[1.5%] Compiling analyze_fft1024.cpp...
[2.3%] Compiling analyze_fft256.cpp...
[3.0%] Compiling analyze_notefreq.cpp...
[3.8%] Compiling analyze_peak.cpp...
[4.5%] Compiling analyze_print.cpp...
[5.3%] Compiling analyze_rms.cpp...
[6.1%] Compiling analyze_tonedetect.cpp...
[6.8%] Compiling control_ak4558.cpp...
[7.6%] Compiling control_cs4272.cpp...
[8.3%] Compiling control_sgtl5000.cpp...
[9.1%] Compiling control_wm8731.cpp...
[9.8%] Compiling effect_bitcrusher.cpp...
[10.6%] Compiling effect_chorus.cpp...
[11.4%] Compiling effect_delay.cpp...
[12.1%] Compiling effect_delay_ext.cpp...
[12.9%] Compiling effect_envelope.cpp...
[13.6%] Compiling effect_fade.cpp...
[14.4%] Compiling effect_flange.cpp...
[15.2%] Compiling effect_midside.cpp...
[15.9%] Compiling effect_multiply.cpp...
[16.7%] Compiling effect_reverb.cpp...
[17.4%] Compiling filter_biquad.cpp...
[18.2%] Compiling filter_fir.cpp...
[18.9%] Compiling filter_variable.cpp...
[19.7%] Compiling input_adc.cpp...
[20.5%] Compiling input_adcs.cpp...
[21.2%] Compiling input_i2s.cpp...
[22.0%] Compiling input_i2s_quad.cpp...
[22.7%] Compiling mixer.cpp...
[23.5%] Compiling output_dac.cpp...
[24.2%] Compiling output_dacs.cpp...
[25.0%] Compiling output_i2s.cpp...
[25.8%] Compiling output_i2s_quad.cpp...
[26.5%] Compiling output_pt8211.cpp...
[27.3%] Compiling output_pwm.cpp...
[28.0%] Compiling output_spdif.cpp...
[28.8%] Compiling play_memory.cpp...
[29.5%] Compiling play_queue.cpp...
[30.3%] Compiling play_sd_raw.cpp...
[31.1%] Compiling play_sd_wav.cpp...
[31.8%] Compiling play_serialflash_raw.cpp...
[32.6%] Compiling record_queue.cpp...
[33.3%] Compiling spi_interrupt.cpp...
[34.1%] Compiling synth_dc.cpp...
[34.8%] Compiling synth_karplusstrong.cpp...
[35.6%] Compiling synth_pinknoise.cpp...
[36.4%] Compiling synth_simple_drum.cpp...
[37.1%] Compiling synth_sine.cpp...
[37.9%] Compiling synth_tonesweep.cpp...
[38.6%] Compiling synth_waveform.cpp...
[39.4%] Compiling synth_whitenoise.cpp...
[40.2%] Compiling data_ulaw.c...
[40.9%] Compiling data_waveforms.c...
[41.7%] Compiling data_windows.c...
[42.4%] Compiling memcpy_audio.S...
[43.2%] Compiling Wire.cpp...
[43.9%] Compiling WireKinetis.cpp...
[44.7%] Compiling SPI.cpp...
[45.5%] Compiling SPIKinetis.cpp...
[46.2%] Compiling cache_t3.cpp...
[47.0%] Compiling card_t3.cpp...
[47.7%] Compiling dir_t3.cpp...
[48.5%] Compiling fat_t3.cpp...
[49.2%] Compiling File.cpp...
[50.0%] Compiling file_t3.cpp...
[50.8%] Compiling init_t3.cpp...
[51.5%] Compiling SD.cpp...
[52.3%] Compiling SerialFlashChip.cpp...
D:/arduino-1.8.2/hardware/teensy/avr/libraries/SerialFlash/SerialFlashChip.cpp: In static member function 'static bool SerialFlashChip::begin(SPIClass&, uint8_t)':
D:/arduino-1.8.2/hardware/teensy/avr/libraries/SerialFlash/SerialFlashChip.cpp:338:10: error: use of deleted function 'SPIClass& SPIClass::operator=(const SPIClass&)'
  SPIPORT = device;
          ^
In file included from C:/Users/kurte/Documents/Arduino/libraries/SPI/SPI.h:18:0,
                 from D:/arduino-1.8.2/hardware/teensy/avr/libraries/SerialFlash/SerialFlash.h:32,
                 from D:/arduino-1.8.2/hardware/teensy/avr/libraries/SerialFlash/SerialFlashChip.cpp:28:
C:/Users/kurte/Documents/Arduino/libraries/SPI/SPIKinetis.h:184:7: note: 'SPIClass& SPIClass::operator=(const SPIClass&)' is implicitly deleted because the default definition would be ill-formed:
 class SPIClass {
       ^
C:/Users/kurte/Documents/Arduino/libraries/SPI/SPIKinetis.h:184:7: error: non-static reference member 'KINETISK_SPI_t& SPIClass::port', can't use default assignment operator
C:/Users/kurte/Documents/Arduino/libraries/SPI/SPIKinetis.h:184:7: error: non-static reference member 'const SPIClass::SPI_Hardware_t& SPIClass::hardware', can't use default assignment operator
[Build] Error occurred.
(Showing Stino build)

The issue is with the SerialFlashChip class (part of the SerialFlash library)

In this class, there is a static reference variable:
Code:
static SPIClass& SPIPORT = SPI;

And the main code then uses this, when calling SPI, example:
Code:
void SerialFlashChip::wait(void)
{
	uint32_t status;
	//Serial.print("wait-");
	while (1) {
		SPIPORT.beginTransaction(SPICONFIG);
		CSASSERT();
		if (flags & FLAG_STATUS_CMD70) {
			// some Micron chips require this different
			// command to detect program and erase completion
			SPIPORT.transfer(0x70);
			status = SPIPORT.transfer(0);
			CSRELEASE();
			SPIPORT.endTransaction();
			//Serial.printf("b=%02x.", status & 0xFF);
			if ((status & 0x80)) break;
		} else {
			// all others work by simply reading the status reg
			SPIPORT.transfer(0x05);
			status = SPIPORT.transfer(0);
			CSRELEASE();
			SPIPORT.endTransaction();
			//Serial.printf("b=%02x.", status & 0xFF);
			if (!(status & 1)) break;
		}
	}
	busy = 0;
	//Serial.println();
}
However it appears like the code is developed to allow me to change to use a different SPI object by passing it into the begin method:
Code:
bool SerialFlashChip::begin(SPIClass& device, uint8_t pin)
{
	SPIPORT = device;
	return begin(pin);
}
This is where compiler errors out.

My understanding of references is that once they are set at the variables definition it can not be changed.

And if I were to try to call this with something like:
Code:
 myspiflashchip(SPI2, 5)
That it would try to copy the contents of SPI2 object over the top of SPI object and not assign the new address. But this errors as this class did not provide an assignment operator...

My question is, is there a way to do this in the SPIClass code?

Up till now my knowledge tells me that if I wanted the SerialFlashChip class to handle the multiple SPI buses like this with references, I would need to define the SerialFlashChip to take a reference to the SPI Object on it's constructor, like:
Code:
SerialFlashChip::SerialFlashchip(SPIClass &device) : SPIPORT(device) {};

Or if I wanted to be able to change it on the fly with the Begin method, I would then instead use pointers instead of reference.

But hopefully I am missing something, as I did something very similar with my own code yesterday and then changed to using pointers.

So any hints would be greatly appreciated!
 
What SerialFlash is doing makes no sense to me. You are correct that "bool SerialFlashChip::begin(SPIClass& device, uint8_t pin)" is trying to copy the SPIClass object. For assignable SPIClass classes it would mess up the SPI object, which might now refer to a different port.

C++ gives you a default assignment operator, if all members are individually copy-assignable (which references are not).

IMO, your SPI class shouldn't support copying or assignment and the SPI consumer should use a pointer if it wants to support changing the SPI port after construction.

This is the SerialFlash commit that added the strange begin():
https://github.com/PaulStoffregen/SerialFlash/commit/ea513149def4a96b3f200f3f1dda9ea176eae41c
 
Back
Top