-
-
Notifications
You must be signed in to change notification settings - Fork 346
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
Hardware SPI: Issues i discovered and potential solutions (API Discussion) #618
Comments
Byte orders/shifting logic and how to let the HW do the JobAs we all know the ESP has a 32 bit architecture. This includes the SPI register and bus. This is basically what the actual SPI implementations tries to do within the loop below:
I have not yet fully understood all the &= ~() != magic in this code but leave that for now. If you mess the byte orders up you get the wrong data sent out as you can see in the picture below. But that's no big deal. We just need to tell the ESP hardware to shift out the registers the way we need them.
That's much easier and gives me more confidence to be right ;) And here is the result: |
Registers & buffer sizes and how to send long data blocksThe HW SPI bus is using a defined memory block to shift out and receive data to/from the bus. So here is the register definition
So we have 16 ? or do we have 32 registers ? Well lets check how we set up the block length for the submission: Here is the code snippet:
First step is to to calculate the number of bits to send starting from 0. Next is to tell the ESP the number of bits to send. This info goes into the Register SPI_USER1(HSPI). Here is the structure of the register SPI_USER1
So out of that definition we know that the max amount of data the ESP can send in one HW transaction is The SPI_WO register is used for sending and receiving data. If that's done in the one HW transaction than it should be guaranteed that the buffer is sent out before it's overwritten with received data (have not tested that yet) I found somewhere a hint that it's possible to split up the Register into a TX and RX address. Maybe that when does magic SPI_W16 through SPI_W31 come into place. So and finally looking into the SPI cod we have in Sming:
So we have no option to set individual buffer length for RX nor TX. I correct implementation should loop in blocks of 64 bytes or send a error message or let the user build a external loop. NOTE: For whatever reason the ESP stops clocking out after 32 Bytes for the MISO line. Might be a Bug or even an error on network Layer 8 (me). |
More control registers and features that might come in handy (and should be considered in the API)Looking at the spi_register.h file there are tons of registers to control the data flow. Many of those registers come in very handy with some devices. Most notably the command, address and dummy registers. This allows you to keep you code clean. So you can send in command sequences and data without the need to copy or even memcpy command and data together before you setup a transaction. Here is a sample of a sequence from the ArduCAM spec. Another import setting are the dummy bits. They are used to deal with latency of the slave device. The ESP can deal with that. So you can tell the bus to ignore the dummy bits and start moving data into the register from bit xx on. As for the other control registers. I did not found any reasonable sour of documentation what they do. Very own problems when using HW Client Selector on PORT 15Ok the last thing to think about is the HW controlled SS or CS signal. I have not found any way to get more control on this signal. For devices that require the CS line to be low until all data is sent or received that is a problem. Once you sent/recv the first 64 bytes the signal will go high and might set the client into another stage where you cannot continue to read. Again check the timing diagram above. This is the sequence you will use when you want to get a image or video stream. Obviously that will exceed 64 bytes. As a result you cannot use HW CS/SS for this type of device. Instead you need to use CS signal on a different PORT than 15 that you can control within your code. |
API QuestionsI now have a functional complete (or more complete) HW SPI implementation ready that covers most of the topics discussed above. Before i put more effort into it to prepare a PR i like to get your opinions an how to define the API for that lib. There are several option.
THX for your votes |
I say a mix of 1 and 3,arduino compatible is very nice to have, and a base On Fri, Feb 26, 2016, 19:24 Harry Böttcher notifications@github.com wrote:
|
I stay for 1 and indeed 3! You work analyzing spi is awesom! |
@harry-boe thanks for such a detailed SPI analysis. As for the questions i also vote 1 & 3 |
@harry-boe : |
OK, I will go that way -> Base class that more or less defines the methods we see in the Arduino API's |
I'm late to the party, |
I have now all sorted and the ArduCAM working as a proof of concept. I will go for the Arduino SPI api resp. the extended Arduino DUO SPI API It has a really nice features using SPISettings. This allows you to have different setting for different devices including speed, byte order etc.
I also like the concept how they deal with transactions: That's really convenient. On top of that you can of course still use SPI.beginTransaction()
|
so basically aruinocam works, can you also share that, and which cam to buy? On Wed, Mar 2, 2016 at 12:51 AM, Harry Böttcher notifications@github.com
|
i create a PR for the ArduCAM once the code is polished and fully tested. |
@harry-boe : I have the impression that a number of them are inter-related by the SPI discussion. Can you give me an update on status, so that I can clear up/merge outstanding PR's ? |
I have the API and BASE classes now ready. The changes have quite some impact for several LIBS and Samples. It does compile but it needs testing! I have not yet done the PR as the implementation for the HW SPI is still incomplete but if someone finds time to test other devices using SW SPI please get the code from my repo |
On Wed, Mar 2, 2016 at 11:02 AM, Harry Böttcher notifications@github.com
|
@alon24 |
PR is out so please test what you can |
I am wondering one thing. esp8266 modules about $3, arducam $25, and total price about $30. you can buy 2MP network cam with many features and enclosure for this price. why we need this? |
Fair point. Question as the ESP does not sum up. Why would anyone buy a ArduCAM at all ? For me it's about heaving full control on the cam and being able to have my own network protocol. |
Fair enough. How about streaming? can esp and arducam handle 10-15 fps jpeg streaming? |
Well i don't know yet but it should work. |
so can new hwspi run on 80mhz ? |
Theoretically YES If you set the SPI Clock speed to 80'000'000 using the SPISettings it will set the clock divider to 0 and this will tell the ESP to use the System clock as SPI clock. Note: Clock definitions between SysClock and half sys Clock do not have a valid clock divider and therefore the speed will be set to half sys clock. However i did not found a test device that can go that fast nor is my Logic analyser capable of capturing that fast. |
all the findings are implemented and merged with pr #642 |
I have spent endless nightly hours with the ESP and Logic analyser to figure out how the HW SPI bus is working and why a had so many issues with the current (and other implementations).
Fist of all, all my finding do not apply for the SPISoft implementation. That implementation is basically derived from the TatFS/SD card implementation from ChaN. That's a solid and very efficient peace of code.
The current HW SPI implementation is ok when submitting a few bytes. Basically one 32bit register.
But it fails when sending or receiving bigger data packets. As most of the sample projects in Sming (i.e Displays, MUX) just send/rec byte by byte the issues have not yet posed up.
For readability i will split up the my various findings in separate posts. to cover them one by one.
And of course i still might be wrong and have not yet tested all my thoughts and theories. However i'm close to a final implementation and like to discuss here how we should define the API and how we will test and go on with the current implementations.
Overview on the findings a made:
And last but not least the question how to build up a reasonable API. Use the Arduino API, go with Base classes SW HW, enable the full feature set etc.
The text was updated successfully, but these errors were encountered: