Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chip Select (NSS) in SPI transfers #10

Open
epninety opened this issue Apr 19, 2021 · 6 comments
Open

Chip Select (NSS) in SPI transfers #10

epninety opened this issue Apr 19, 2021 · 6 comments

Comments

@epninety
Copy link

Trying to send multiple bytes in an SPI transfer from buck50.py, I'm unable to find a method to keep /CS (NSS) asserted for the complete transfer. Presently /CS rises briefly after each byte is sent, which spi devices read as completion of the transfer.

e.g. I enter 'spi' to get to spi mode, then '12 34 56' to send three bytes of data.
On the scope, I see /CS rise for ~2uSec between bytes.

Have I missed a trick in the documentation, is there a way to hold /CS low for the complete transfer?

Current settings
mode : master
xmit-only : disabled
snoop : disabled
select : hardware
baud : 281.25KHz
endian : msb
idle : low
phase : 1st
miso : open-drain
pull : up
speed : 2MHz
nss : active
tx-data : 00
rate : unlimited
busy-wait : 1ms
rx-wait : 1ms
nss-time : 100μs(error:+1.35525e-08ps)
ascii-num : numeric
end : END

(Hardware is a custom board with a genuine STM32 fitted.)

@epninety epninety changed the title Chis Select in SPI transfers Chip Select (NSS) in SPI transfers Apr 19, 2021
@thanks4opensource
Copy link
Owner

How did you choose the value fornss-time=100μs? In themode=master nss=active SPI configuration, buck50 lowers PA4/NSS1 at the beginning of a byte transfer, waits nss-time to allow the data to be serially shifted out the PA7/MOSI port, and then raises PA4/NSS1. Can you set nss-time to baud_rate * 8 bits * num_bytes + extra for CPU overhead? Alternately, can you just permanently (for the duration of the test) set NSS low using nss=low, or even more simply tie the slave's select input to directly to ground? Do you need to test the its ability to dynamically respond to its slave select line?

Note that the ST SPI peripheral's handling of NSS output in master mode is very limited. RM0008 documents the spectacularly useless "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." I wasn't able to find any way for hardware to lower and then re-raise the NSS output at the beginning and end of an 8 (or 16 bit) SPI transfer, much less at the beginning and end of a multi-byte packet.

At one point it occurred to me that there are many spare ports when buck50 is in SPI mode and they could be used (under software control) to select multiple slaves on an SPI bus. The interactive mode would then be something like "3 12 34 56" to select the slave connected to port PA3 and send it those three bytes. I might add that feature someday if I have use for it, but I currently don't and, as you've discovered, buck50 is already complex enough.

@epninety
Copy link
Author

baud_rate * 8bits * num_bytes = 85us for 3 bytes at 280kHz ? So 100us seems to be about right?

But from the scope, nss-time seems to set the time delay between NSS assertion and the actual byte transfer?
So with nss-time=100us...

NSS goes low
~100us delay
1 byte is clocked out,
~100us delay
NSS goes high
~2us delay
NSS goes low
etc. etc.

I've never understood how hardware driven NSS is supposed to be useful on STM32, but I assumed they knew something I didn't. I can't think of any SPI device that could be controlled with 8bit transactions. Even 16 bit transactions aren't very useful for many (most?) that I've used in the past. In my own code previously I configured the NSS pin as GPIO, then drop and raise it manually at the start and end of the transaction.

I will hardwire the NSS for now, and think about a 'proper' solution later if I need it.

I like your idea for multiple slaves, my testboard has jumpers at present to select devices on the target hardware. As you say, buck50 is complex enough, and very capable. Thank you for your efforts.

@thanks4opensource
Copy link
Owner

You're welcome. Glad you've found it useful.

Reviewing the code, it looks like I should remove the nss-time parameter and instead check Spi::Sr::BUSY. I seem to recall trying something like that without success, but it might have been my own misunderstanding and/or bug.

Removing thenss=active value and splitting it into something like=single and =multi to assert/de-assert the slave select on a per-byte or per-packet basis might also be nice. But if also doing the multiple select outputs it would then need to be independently settable for each port , and once again the complexity starts growing exponentially. I kept running into this issue during buck50's long development and always had to decide where to stop.

@epninety
Copy link
Author

What is the use case for =single though? I still cant think of any SPI device I've used where it would be useful.

It seems simpler and cleaner to consider each line entry as a discrete SPI transaction, so drop NSS at the start, and raise it at the end. (8 bit transactions are still possible of course, it just means entering one byte per line.)

Alternatively, add a control character for the NSS line. Some thing like \ 12 34 / \ 56 / is probably self explanatory, but I think it's just adding unnecessary complication when 12 34 <cr> 56 <cr> would achieve the same thing.

@thanks4opensource
Copy link
Owner

Just because neither of us can think of a use for =single right now doesn't mean there isn't any. ;) For example, I use SPI (both from buck50 and otherwise) for generic serial I/O, things like APA102 "smart" LEDs. Something/somebody/somewhere/someday might want NSS per-byte.

Your embedded raise/lower controls are even more general the my =single/=multi configuration scheme. Yes, using separate buck50 SPI lines could do the same thing in terminal mode, but keep in mind that buck50 SPI (and I2C and USART) can also be accessed via the socket and pty interfaces.

@epninety
Copy link
Author

OK, hands up, I was wrong. While working on something else today, I found a use for an 8 bit SPI transfer. You can set or lift the Write Enable latch on a 25AA256 E2PROM.

Of course, you still can't actually write any data to it, or read from it, so it's not very useful. And if you hold NSS low, you'll only get one transaction, so the only way to actually write to the device would be to go in to spi mode, clear the latch, exit SPI mode, re-enter SPI mode, and then write some data.

At least when reading the device, you could go into SPI mode, and then read the whole of the device in one long transaction of just over 32k bytes. That's probably best done over the socket or pty interfaces I would think. I'd probably lose count otherwise :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants