Spark Logic

SPI + ISR + SPCR etc.

HexTank Fri Sep 30, 2016 11:03 am

So I’ve just moved over to the Baite MM, to utilise the faster SPI compared to the arduinos. Now, I’ve tried to move a simple sketch across and hitting compile issues verbatim.

Things aren’t declared such as SPCR, SPDR etc. and using the ISR macro yields constructor errors and what not.

Have these things been setup for the STM32 side of things or is it pragmatically different? I’m not interested in DMA or anything, I’m just looking for a simple interrupt firing when when data has been received as an SPI slave.

Replies

HexTank Sat Oct 08, 2016 2:35 pm

RogerClark wrote:So just use a different pin for you CS and use digitalWrite to control it

HexTank Mon Dec 12, 2016 8:47 pm

It seems in the effort for me to get USBSerial working and getting the new codebase, I lost my SPI functionality, now, I can’t remember if I made these fixes locally or the code base has been changed.

Regardless, I don’t have this code base set up via git (I download as a zip) so these are the changes that may need to go in to the codebase for SPI slave to work. Luckily I backed up the working version so I could do a diff, else, I’d be crying right about now. ;)

It’s the lower of the two that’s needed, the one with _currentSetting->dataSize is.

diff -r hardware/Arduino_STM32/STM32F1/libraries/SPI/src/SPI.cpp hardware_2/Arduino_STM32/STM32F1/libraries/SPI/src/SPI.cpp
145c145
< uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT | SPI_SW_SLAVE | SPI_SOFT_SS);
—
> uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE | SPI_SOFT_SS);
153d152
<
160,164d158
< if (_currentSetting->dataMode >= 4) {
< ASSERT(0);
< return;
< }
< uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | SPI_DFF_8_BIT/* | SPI_CR1_SSI | SPI_SW_SLAVE*/);
166a161
> uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE);
198c193,194

stevestrong Mon Dec 12, 2016 11:53 pm

HexTank wrote:
> uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE);
198c193,194

HexTank Tue Dec 13, 2016 12:46 am

It does work with SPI_SW_SLAVE, that flag is missing in GitHub and is what I had previously, I also change to take dataSize from settings rather than it being fixed. What does RX only bring to the table? I thought that just made comms half duplex, are you suggesting they’re interchangeable?

stevestrong Tue Dec 13, 2016 8:20 am

HexTank wrote:It does work with SPI_SW_SLAVE

HexTank Tue Dec 13, 2016 10:49 am

Sorry, the diff is a little confusing, basically, current source in github won’t work correctly as SPI slave, the SS is totally ignored and the board is active, as in, MISO is active which conflicts with any other devices connected.

Setting SPI_SW_SLAVE makes the board behave correct, as in, it adheres to the SS pin being high (disconnected) or low (active).

RM0008, page734 wrote:
This bit is also useful in a multislave system in which this particular
slave is not accessed, the output from the accessed slave is not corrupted.

Yes, because you lose the sending and receiving at the same time, full duplex.

stevestrong Tue Dec 13, 2016 12:11 pm

HexTank wrote:…current source in github won’t work correctly as SPI slave…
…Setting SPI_SW_SLAVE makes the board behave correct…

HexTank Tue Dec 13, 2016 12:39 pm

Close, SPI_SW_SLAVE | SPI_SOFT_SS is set in SPIClass:updateSettings() neither is set in SPIClass::beginSlave().

The only change that would really affect working and not working would be to apply SPI_SW_SLAVE in SPIClass:beginSlave.

updateSettings() also uses _currentSetting->dataSize rather than SPI_DFF_8_BIT, which I also changed in beginSlave(), this won’t affect the disregard of SS but is a discrepancy nonetheless.

stevestrong Tue Dec 13, 2016 12:52 pm

Hm, sorry but I cannot see any discrepancy here, data size (DFF) and SSM seems to have nothing in common.
And I am currently using SPI slave application where I set SSM = 0. And is working, because I apply the SS signal from the master to the SS pin of the slave.

HexTank Tue Dec 13, 2016 1:06 pm

The size will only affect if you decide to use 16bit data transfer, which is rare.

That’s great it works for you, how many slaves do you have? I have a bespoke device that has its own SPI slave (SD Card) and has a break out for extra SPI slaves along with a master SS, which I connect to a maple mini, so two slaves, it doesn’t work correctly as SS is ignored.

I’ve captured the data via Saleae, the bespoke device is controlling SS, if I don’t have SPI_SW_SLAVE set for the slave, SS on the maple is ignored, which is easy to tell as MISO on the maple should go hi-z when SS is high.

if you’re only testing with one SPI slave on the SPI network, the test is wrong.

Also, to clarify, by not working, I mean there’s contention on the SPI bus, so when I’m talking to the other SPI slave, they’re both active on the bus.

stevestrong Tue Dec 13, 2016 2:03 pm

OK, so the things are getting more clearly: you have one master and two slaves.

What is still unclear is whether the SPI master can also read data from MM or only transmits to MM?
In my case, I only transmit data from one master to one slave, that’s why I can use RXONLY (output disabled).

Btw, the functionality of NSS pin in slave mode is detailed in RM0008 pages 697 and 694.
Page 697:
4. In Hardware mode (refer to Slave select (NSS) pin management on page 694), the
NSS pin must be connected to a low level signal during the complete byte transmit
sequence. In NSS software mode, set the SSM bit and clear the SSI bit in the SPI_CR1
register.
This actually is explaining that what you are doing is software mode (SSM=1, SSI=0), and is also supposed to work as expected.
I was previously wrong, because I suggested SSI to be set to 1, but this would mean “unselect”. So correctly SSI should be 0 for permanent active selection. This also explains why your MM is always active on the bus…

And on page 697:
• Software NSS management (SSM = 1)
The slave select information is driven internally by the value of the SSI bit in the
SPI_CR1 register. The external NSS pin remains free for other application uses.
• Hardware NSS management (SSM = 0)
Two configurations are possible depending on the NSS output configuration (SSOE bit
in register SPI_CR2).
– NSS output enabled (SSM = 0, SSOE = 1)
This configuration is used only when the device operates in master mode. The
NSS signal is driven low when the master starts the communication and is kept
low until the SPI is disabled.
– NSS output disabled (SSM = 0, SSOE = 0)
This configuration allows multimaster capability for devices operating in master
mode. For devices set as slave, the NSS pin acts as a classical NSS input: the
slave is selected when NSS is low and deselected when NSS high.
This is what I am using, hardware management (SSM = 0, [SSI=X], SSOE = 0): when input SS pin is low, then my slave is selected and receives the transmitted data.

HexTank Tue Dec 13, 2016 2:32 pm

Yes, the master both sends and receives (it mainly receives data from the MM as I’m using it as a virtual SD card that’s actually squirting data from the PC – which now currently works thanks to the tips of the serial questions too – thanks of that :) ), this is to multiplex the data so it’s quicker.

Ok, so it works, because it should, but in software. I’d prefer it to be hardware and I’m not even sure how I ended up with what I did, it might have been a case of seeing the commented out SPI_CR1_SSI and SPI_SW_SLAVE and trying to decipher the docs and it magically starting working. :)

Right, so by SPI_SW_SLAVE not being active and SSI being 0 means that’s where the contention happened because it was always live? Ok, that makes sense. So this means the correct thing to have done would be to set SPI_CR1_SSI? (I’m currently rewriting my sketch at the moment so not in a position to verify just yet)

Thank for the help btw, much appreciated. It does beg the question whether the SPI library should be changed so setting can be set in the sketch without the need to modify the libraries themselves.

stevestrong Tue Dec 13, 2016 3:05 pm

Your problem with the software SPI management, setting the SS signal always active per software, is that you reserve/block the SPI bus continuously,conflicting with the other slave.

If master should be able to read data out from slave, please don’t set SPI_RXONLY pin.

As the slave normally doesn’t know when exactly the master wants to communicate with him, I would strongly suggest to use HW SS pin management, by setting SPI_SW_SLAVE (SSM bit) to 0, the SS select signal should activate the MM according to the master control needs.
The master should selectively select one or the other slave, as you already know, but only one at the time.

So far I cannot see why to change the SPI software, your needs can be covered in general by the actual software.
Or do you feel that something is missing?

HexTank Tue Dec 13, 2016 3:20 pm

Oh man, so this was actually a case of removing the SPI_SW_SLAVE | SPI_SOFT_SS from SPIClass:updateSetting() and leaving SPIClass::beginSlave() alone? I’ve just tried that and both slave devices are playing nicely, although as you can imagine, I have little faith. :)

Regarding SPI class, it would be nice to set whether it’s software / hw slave in the class itself rather than trying to override it externally to the class.

stevestrong Tue Dec 13, 2016 4:02 pm

HexTank wrote:… although as you can imagine, I have little faith. :)

HexTank Tue Dec 13, 2016 4:16 pm

Well that much I knew, and I guess the main problem is why updateSettings gets called as that’s the master part, I need to get me a stlink to help me debug these things.

But at a guess, as I’m using SPI1 with

SPI.setModule(1);
SPI.beginSlave();
spi_irq_enable(SPI.dev(), SPI_RXNE_INTERRUPT);

stevestrong Wed Dec 14, 2016 9:36 am

Indeed, SPI will automatically setup itself in master mode when including SPI.h in sketch.
So you have to reprogram it to slave, and calling beginSlave() should do the reprogramming.
setModule() is only needed when you are using SPI2, too.

Sign in to reply