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.
I did see SPIClass is used looking at http://www.stm32duino.com/viewtopic.php?t=891&start=10 and googling thereafter which led to github, unfortunately, the PR hasn’t been pulled, and nowhere else on the site is there any mention on on how the handle interrupts, I found than on another external site. The SPIClass seems incomplete, or rather, is if it’s to integrate slave as well as master mode.
I have all the bits I need to hit the hardware now and bypass the libs.
Thanks for the lesson in searching, it was a great help.
Ciao.
Thanks for the lesson in searching, it was a great help.
SPI.setModule(2);
SPI.beginSlave();
spi_irq_enable(SPI.dev(), SPI_RXNE_INTERRUPT);
There is weak default_handler in file STM32F1/cores/maple/libmaple/stm32f1/performance/isrs.S
You need to override this weak handler by writing your own __irq_spi1 function.
I tried thus.
void __irq_spi1()
{
digitalWrite(33, LOW);
}
extern "C" {
void __irq_spi1(void)
{
digitalWrite(33, LOW);
}
}It’s a shame the compiler doesn’t say where the previous declaration was from (I’m assuming it’s the one in the isrs.S)
Ahh, well, this compiles and works.
extern "C" {
void __irq_spi1(void);
}
void __irq_spi1(void)
{
digitalWrite(33, LOW);
}
https://my.st.com/public/STe2ecommuniti … tviews=290
Given the way it’s rigged up now with the Maple code, it’d be reading / writing 32bit values.
Ahh, well, this compiles and works.
This interrupt is now serviced, although it still hangs, so I guess it’s going to be harder to track the cause of that.
Reading the data in to a buffer so I can write out the values in Loop() which is working although the values I’m receiving are all 0xFF, which is wrong. The values sent from the STM to the master are all 0xFF too.
Oddly enough, my ISR is basically a spi.read in to a variable and pass that on to spi.write, I’d I change that variable, say, assign it zero before using it in the spi.write, it hangs.
There’s something a bit sensitive about it all, like I said in my previous post, I don’t think the DR access is correct. Even the maple source has casts before reads / writes, thats redirections casts rather than casting the result.
Next step, rest until I have some more ideas on what might be wrong.
But there are so many things that can go wrong with interrupts, i’m glad that for the moment i’m not working with them :p.
I have a Billy no mates scope on its why from China just to verify all that stuff is OK, but SS and CLK clearly work.
No matter how many times I checked it appears I still had SCLK and SS the wrong way around, that alone was sure to cause issues. ![]()
Now, I know I have MISO and MOSI the wrong way around, having them the correct way around causes another SPI device to fail (which is bolted on to the master), so, this begs the question.
Is SS on SPI1 as slave just ignored? as in, when it goes high, it doesn’t go in to a high impedance state?
It has a special function and is not designed to be used as CS.
Basically its some weird function developed by STM, which no one else uses.
We tried to disable this weird use of SS, but I am not sure it was successful. So its better to use a completely different pin for CS functions
I plugged all my wires to SPI2 and it worked, so I thought maybe the analyser was interfering somehow, so removed those probes and put wires back to SPI1, still works. Put probes back on and still works.
For curiosity should anyone fall upon this post. ( a little crude, but will tidy it up after I have finished revelling in success )
#include <SPI.h>
char buf [100];
volatile byte pos;
volatile boolean process_it;
void setup()
{
Serial.begin(9600);
pos = 0; // buffer empty
process_it = false;
SPI.setModule(1);
SPI.beginSlave();
spi_irq_enable(SPI.dev(), SPI_RXNE_INTERRUPT);
pinMode(33, OUTPUT);
digitalWrite(33, HIGH); // turn the LED on (HIGH is the voltage level)
}
extern "C" {
void __irq_spi1(void);
}
void __irq_spi1(void)
{
digitalWrite(33, LOW); // toggle onboard LED to see if we crash out
short b = spi_rx_reg(SPI.dev()); // read data which shoould flush RXNE
spi_tx_reg(SPI.dev(), b); // echo data back to master
if (pos < sizeof buf) // append to a buffer and GTFO of the interrupt
{
buf [pos++] = b;
process_it = true;
}
digitalWrite(33, HIGH); // turn LED back on, we got this far.. oh my.
}
void loop()
{
delay(1000);
Serial.print("*"); // in case we crash whilst LED is still on :D
if (process_it)
{
buf [pos] = 0;
for( int i=0; i<12 && i<pos; i++ )
{
Serial.print(buf[i], HEX);
}
pos = 0;
process_it = false;
}
}
RogerClark wrote:Dont use the SS pin for CS.
It has a special function and is not designed to be used as CS.
Basically its some weird function developed by STM, which no one else uses.
We tried to disable this weird use of SS, but I am not sure it was successful. So its better to use a completely different pin for CS functions
This is known bug for the F103 device, which a lot of people (not just Arduino users) have complained to ST about.
But from what I recall, ST say that the way it operates is “by design” (even though it looks like a bug)
So just use a different pin for you CS and use digitalWrite to control it
Note. For some devices a hardware SS pin just doesn’t work because of the timing. i.e NSS may go low just a few nS before the data is clocked, and I know at least one device which requires delays between CS going low and the first byte of data being received
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
> uint32 flags = ((_currentSetting->bitOrder == MSBFIRST ? SPI_FRAME_MSB : SPI_FRAME_LSB) | _currentSetting->dataSize | SPI_SW_SLAVE);
198c193,194
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.
…Setting SPI_SW_SLAVE makes the board behave correct…
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.
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.
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.
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.
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.
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?
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.
But at a guess, as I’m using SPI1 with
SPI.setModule(1);
SPI.beginSlave();
spi_irq_enable(SPI.dev(), SPI_RXNE_INTERRUPT);
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.




