Problems setting SPI Speed

So, since I’m thinking about it, here’s what I wrote in place of the two available Spark Adafruit MAX31855 libraries that are available.

Critique and suggestions for improvement welcomed, but email it to me rather than post it here, since that might be considered by some to be harmful to me, somehow. My email is my username here @ gmail.com.

When I started using the Adafruit library, I experienced the EXACT same issue that the originator of this thread mentioned. SPI speed could not be adjusted, I could not change the SPI mode, nor the byte order. After some digging, I discovered why; it was all hardcoded into a bitbanged SPI implementation that used the same pins as the SPI hardware… So I fixed that, and the link above shows the outcome. Much smaller, which means a lot on a platform with 108kiB of program space and 20kB of RAM.

Hope it helps someone.

@naikrovek, I want to be clear that you ARE welcome here and it is because of the importance of openness and valuing other’s work that we may, IMO, have overacted slightly :smirk:

As far is critique or feedback, since you are on github, I would say that is the best place to make comments. I can tell you right now that you can optimize even more by using direct bit operations versus digitalWrite() but in the case of reading a temperature, it would be overkill. Nice job on the optimization. :smile:

I agree. In the interests of code clarity, I elected to use digitalWrite() for the CS line for this.

1 Like

@naikrovek, a great example of community support and synergy is that I ported a tough (Core wise) RGB Matrix Panel library for @Dave who wanted to use it for a personal occasion. My original release was not optimized and I later released a more optimized whole-port version. But then @ScruffR (the little devil) went and optimized it even more, squeezing even more performance out of a tricky ISR. All that to say that we all learn from and feed off each other in this community. This is what makes it great and welcoming. :smile:

1 Like

@peekay123 Still on the optimization thread, I found a version on the ILI9341 library that has been highly optimized for the DUE, it shows some very impressive speed improvements using SPI DMA, so … before I go and sink hours into taking a stab at porting it over to the Spark do we know if SPI in DMA mode on the Spark?

You can find the optimized version written for the Arduino-DUE here It’s impressive - they have taken something that takes over 14 seconds with UTFT down to 1.4 seconds using this optimized library

@mtnscott, the current SPI implementation is a simple port of the Arduino version for the sake of compatibility. However, the STM32 does support SPI DMA as implemented by @SaratogaDude here:

So there is definitely a possibility of using DMA. The DUE solution writes out the screen on horizontal line at a time, using a much smaller line buffer (640 bytes). From what I see, it is a very nice implementation. I will absolutely look at porting it to the Core since this is a very popular display especially since it is available with a touch overlay. Nice find! :smile:

1 Like

@peekay123 I started to port the library and completely got stumped with the DMA stuff. This version has specific AVR and SAM3X DMA code but nothing specific to the ST32M we are currently using. I hope you decide to take interest and port the module. It’s got a lot of potential and sure would love to test my code using this library. Let me know if you can’t get to it and I will try and dig in on the DMA stuff.

1 Like

@mtnscott, I am looking into this port. I also think that have SPI DMA in the HAL, just like I2C DMA, is important. :smiley:

@peekay123 Thanks but there is no need for you to invest your energy. I have it working with DMA thanks to the help from @pra.

Interesting comment - I thought a lot about how to use DMA on an LCD display and it needs to be a mix of byte oriented SPI as well as DMA bulk. In my tests I found that the transition point was around 40 bytes (after i squeezed everything from the byte oriented SPI, as well as the bulk DMA) So proper support in the HAL would be for the SPI handler to determine how large a block of data was to be written and then either use byte oriented register transfer, or setup the DMA and use DMA to do the transfer.

Now the additional twist is that sometimes you need to send control bytes and then other times data bytes, so that also plays into how you block up the transfers as you have to manipulate the control lines as well.

Lastly, I was not able to get the DMA1_Channel3_IRQHandler to get called and I had to resort to polling the DMA controller to determine when the transfer was complete. I'm waiting for a new JTAG debugger as my current JTAG debugger appears to not have enough control lines (It's only SWD - I posted on another thread but no answers have come forward), so once I receive the new STLink/V2 I will determine where my interrupts get handled. I searched the compile_server2 branch and could not figure out why my interrupt was not getting called. BTW - the I2C DMA does not use the interrupt either, it polls.

@mtnscott, interesting. I would love to see your code! :stuck_out_tongue: Did you end up using the same line-oriented approach as the Due version?

As for the SPI handler, I think control needs to remain with the user and not in the handler IMO though it does bring up some interesting possibilities in a FreeRTOS environment.

I am no longer using the compile_server2 branch. Instead, I am using the HAL branch with local compiling for all “new” projects since this is will be the future main branch as the Photon and Electron come online. I will investigate the DMA interrupts as well. They may be stubbed out and the fact that they are not used in the I2C DMA may be more for expedience than anything else. Perhaps @mohit can provide some guidance here.

[quote="peekay123, post:34, topic:10060"]
I would love to see your code!
[/quote]Its really messy now (really messy to begin with all of the defines and stuff to support AVR, DUE, ...)

Yes, I kept in the scan line buffer code - and we discovered (@pra found this!) that SPI1 can in fact run at 36Mhz.

I've been afraid to switch to the HAL branch because I've been bashing my head against the wall hitting flash limits w/ current codebase - do you know if HAL branch is larger or smaller wrt flash?

Building tinker gives this:

c:\Users\naikrovek\Desktop\spark\code\firmware>make
Building firmware for Spark core, platform ID: 0
   text    data     bss     dec     hex filename
  12936     632    3564   17132    42ec ../build/target/bootloader/platform-0/bootloader.elf
   text    data     bss     dec     hex filename
  79684    1144   11620   92448   16920 ../build/target/main/platform-0/main.elf

if that helps. Looks like very close to the same size as the master branch of firmware repo to me, but I'm going from memory.

@mtnscott, I love messes! Share when you can pleeeeaaasssee :stuck_out_tongue_winking_eye:

So I guess you CAN set a DIV1 on the SPI clock tree. We need to add that to the firmware for sure!

The HAL branch is basically refactored master branch code with the intent of creating an abstraction layer between the hardware and the rest of the code. As such, for the Core version, I suspect the size does not change much if at all. I’ll have to look at the compiler output to be more precise. The fundamental limitations of the Core are due to the limited flash/RAM environment of the STM32F103 so don’t expect any radical reduction in the use of resources. There may, however, be a more flexible MAKE environment which will allow the selection of Core functionality to be excluded from the compiled target (no I2C for example), making the bin smaller. This is just an (educated) guess for now. :smiling_imp:

In the CMSIS element system_stm32f10x,c functionSetSysClockTo72(), PCLK1 is set to the System Clock/2 (36 MHz) and PCLK2 is set to System Clock or 72 MHz. SPI 1 is using PCLK2 and SPI 2 (CC3000 and external Flash) is using PCLK1. DIV2 (or 0) ia the smallest SPI clock divider you can have. So DIV2 means 36 MHz on SPI 1, and 18 MHz on SPI 2.

2 Likes

@mtnscott, any chance you can post your code :stuck_out_tongue_winking_eye:

@peekay123 Sorry i’ve been away for a bit. The SPI DMA library is waiting for me to finish implementation of DMA read support for the onboard touch screen controller as well as the onboard media card - probably more for the media card than the ts controller. I need to get those working and tested. That work was stalled by running out of flash on my current project. I’ll keep you posted. :wink:

1 Like

@mtnscott, any news on the library?

@peekay123 I have to apologize. I have been distracted the past month with travel. The current version of the library is incomplete. I have to implement the SPI DMA read functionality to allow for reading of memory cards as well as reading the touchscreen controller. Not sure when I will be able to get back to it. I will post my DMA speed findings when I get a chance. I mixed DMA and direct port writing to optimize the speed. I found the threshold to be around 40 bytes where below I directly write to the SPI port and above I use DMA. This is due to overhead in setting up the DMA channel.

@mtnscott - looking forward to seeing whatever you post regarding DMA functionality :slight_smile:

@mtnscott, I’d also love to see/implement your code. Any updates?