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

spi.send()/receive() send/receive one byte a time #1745

Closed
zelll opened this issue Jan 20, 2017 · 5 comments
Closed

spi.send()/receive() send/receive one byte a time #1745

zelll opened this issue Jan 20, 2017 · 5 comments

Comments

@zelll
Copy link
Contributor

zelll commented Jan 20, 2017

Expected behavior

A spi.send() should enable HCS pin, send all bits and disable HCS.
spi.receive() should do the similar thing.

I can use transaction(), but converting between bytes/chars is a little slow for me...

Actual behavior

HCS is endabled/disabled for every byte.

nodemcu-spi

Test code

node.setcpufreq(node.CPU160MHZ)
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 80, spi.HALFDUPLEX)
spi.send(1, {0x12, 0x34, 0x56, 0x78, 0x90})
spi.send(1, "abcdefg")
spi.recv(1, 4)

NodeMCU version

NodeMCU custom build by frightanic.com
branch: master
commit: 81ec366
SSL: true
modules: adc,bit,cjson,crypto,encoder,file,gpio,i2c,net,node,ow,pcm,rtctime,spi,struct,tmr,wifi,tls
build built on: 2017-01-16 08:37
powered by Lua 5.1.4 on SDK 1.5.4.1(39cb9a32)

Hardware

NodeMCU DEVKIT V1.0

@devsaurus
Copy link
Member

I confirm your observation but would propose a different solution: spi.send(), spi.recv() should not manage the HCS pin, but the SS/CS pin should be handled on Lua level.

Why?

  • Having spi.send() etc. handle SS/CS implies that they are monolithic. What if the user wants to have multiple send/recv calls combined while HCS remains active?
  • Toggling HCS is a hardware feature and restricted to one dedicated pin.
  • Real world applications could require a different pin for SS/CS or need to address more than one slave (i.e. more than one SS/CS pin).

If you need SS/CS to span multiple bytes, then use the following approach:

node.setcpufreq(node.CPU160MHZ)
spi.setup(1, spi.MASTER, spi.CPOL_LOW, spi.CPHA_LOW, 8, 80, spi.HALFDUPLEX)
-- disable HSPICS
gpio.mode(8, gpio.INPUT, gpio.PULLUP)
-- enable SS/CS pin as output
gpio.mode(ss_pin, gpio.OUTPUT, gpio.FLOAT)

gpio.write(ss_pin, gpio.LOW)
spi.send(1, {0x12, 0x34, 0x56, 0x78, 0x90})
spi.send(1, "abcdefg")
spi.recv(1, 4)
gpio.write(ss_pin, gpio.HIGH)

@zelll
Copy link
Contributor Author

zelll commented Jan 20, 2017

Thanks for quick reply.

  • I use (HCS OR IO*) to choose a slave. SS/CS for that slave is LOW when it has been chosen and SPI is working. The slave is disabled automatically after SPI transaction. If someone wants to control CS individually, he should use (IO*) only.
  • Current spi.send() is slow. When CPU=80M, SPI=8M, it costs 8.8us to send a byte (1us busy + 7.8us idle bus).

In fact, spi.transaction() works for me. But I need a string version of get_miso() and set_mosi() for performance. I thought spi.send() is the string version of spi.set_mosi() + spi.transaction(), but it is not...
While waiting for ESP32, I have to fight for every GPIO/microsecond on 8266 :(

@devsaurus
Copy link
Member

But I need a string version of get_miso() and set_mosi() for performance.

Ah, I see. The two definitely focus on versatile usage regarding word/bit length and neglect performance aspects. Guess, that can be addressed. How about:

spi.set_mosi()

spi.set_mosi(id, offset, bitlen, data1[, data2[, ..., datan]])
spi.set_mosi(id, offset, string)

With the restrictions that offset needs to be a multiple of 8 and bit length is always 8 in the string version. This would allow to use memcpy() internally to speed up things even further.

spi.get_miso()

data1[, data2[, ..., datan]] = spi.get_miso(id, offset, bitlen, num)
string = spi.get_miso(id, offset, num)

Same restrictions as above apply the variant returning a string.

@zelll
Copy link
Contributor Author

zelll commented Jan 21, 2017

Great to have them. 8-bit is the most common case in real world. However, I still think it is more reasonable to keep HCS low during all bytes in send().

@devsaurus
Copy link
Member

Ok, I'll look into the mosi/miso functions.

However, I still think it is more reasonable to keep HCS low during all bytes in send().

I'm not fully comfortable with this as a new requirement to spi.send(). If we'd exploit the hardware feature to toggle HCS accordingly, we're also restricted by the hardware at the same time. AFAIK the HSPI module can support frames of up to 512 bits (plus 32 bits for address and 16 for command). Thus spi.send() would be able to keep HCS low for max. 64 bytes (+ 6 maybe). Going beyond that border needs GPIO interaction on top.
More complex scenarios can/should make use of the Low Level API functions.

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

3 participants