Go Down

Topic: STM32, Maple and Maple mini port to IDE 1.5.x (Read 690870 times) previous topic - next topic



Slightly off topic really, but I came across another STM32 for Rduino repo last night.
However its for the F0 series not F103


It's for Chinese made UNO clone that uses an STM32F0 device.


Personally I can't see why the company chose to use a F0 chip with only 8k of RAM, but sometimes these alternative repos have useful snippets of code.


Sorry I've not had time to look at your code, it it sounds really interesting.

Hopefully my workload will dismissing later in the week and I can get back to looking at all the new and interesting stuff that you guys have been doing ;-)
Freelance developer and IT consultant


Oric-dan, thanks for the comments.
As of right now, our use of DMA in the SPI peripheral does not prevent you from using SPI.transfer commands to access any other device. It is the job of the sketch to control CS and any other line, besides MISO MOSI and SCLK.

We are thinking on integrating a DMA transfer command in the SPI library, which could take take of firing the SPI DMA for you, when passed some arguments. I would think that as long as we leave the CS lines for the sketch, and setup an easy way of checking when the DMA transfer is over, it should be even easier to use DMA for 2 devices, something like this:

1.- setups a buffer and configure SPI port.
2.- Call SPI DMA with buffer pointer and size of transfer.
3.- DMA function sets up the DMA transfer, starts it, and return to main sketch.
4.- sketch prepares buffer for second device, check if the DMA transfer is over, and if it is, calls DMA function with the pointer for the second device.
5.- If main sketch needs to do normal SPI transfers, then first check that the DMA is not active, and if not, can do normal transfers all day long, and whenever it wants, fire another DMA transfer.

We just need to make clear that the SPI DMA function returns immediately, and it is the job of the sketch to verify it has finished before writting to the bus.

We could also set an additional parameter in the SPIDMA transfer call. If set, the SPIDMA returns immediately and  is the sketch job to confirm it has finished. If the parameter is not set or not provided, the function will not return until the DMA has finished. That way if someone wants to leave that work for the SPIDMA function, he can do. Can be used during troubleshooting also if you suspect your sketch may be overlapping CS toggling with DMA transfers.

What do you guys think on something like that?


@roger, do mean this link for the STM32F0 distro: https://github.com/BestU/STM32_for_Arduino_BSP
You added this link about month ago in your wiki :)
It's seems not to be very useful for us. First thing: Windows only. yeah. (Hopefully Microsoft became more offensive with the restricted driver policy, so we get rid of this OS in the MCU segment, but Apple isn't better...).
A little bit more interesting: the touch driver library (I wouldn't need it) and the CMSIS (with DSP lib), but I think not really compatible and without a FPU no fun at all.
The standard libs are equal or older (SPI,wire...) so no benefit for us.
Indeed it's a little bit strange taking the F0 for a development board. The STM32F103CB is about 2 USD for the "end user" on the chinese market.  



umm. I forgot I'd already posted that link. I must be working too hard ;-)

Freelance developer and IT consultant


just for relaxing:
youtube - I should not take smartphone videos for presentation :)
I did a (awful) video of my maple MIDI mini, synced to REAPER sequencer.
All is working as expected: Sync from REAPER, getting data (song position, note on/note off, CC data (the blue line) and so on. Done with ILI9341 DUE DMA library.
Coding time for this: less than an hour. perfect conditions for a real project!


Mar 25, 2015, 12:09 am Last Edit: Mar 25, 2015, 12:12 am by mrburnette
<...> It is the job of the sketch to control CS and any other line, besides MISO MOSI and SCLK.

We are thinking on integrating a DMA transfer command in the SPI library, which could take take of firing the SPI DMA for you, when passed some arguments. I would think that as long as we leave the CS lines for the sketch, and setup an easy way of checking when the DMA transfer is over, it should be even easier to use DMA for 2 devices, something like this:

What do you guys think on something like that?
Or, SPI could be rewritten to not auto-instantiate, but require the programmer to create the class instance with the DMA channel as part of the argument.  This new class, not replacing the existing one which would remain for compatibility, could be used just like SoftwareSerial to manage multiple DMA channels.  Each instance could then have its own buffer/queuing methodology and callback. 




I'm not sure why we'd need to make a duplicate / new class for SPI with an additional function.

This sounds like it would cause maintenance issues.

I guess we could subclass the existing SPI class with a new SPI class that had an additional function e.g SPIDMATransfer() and also doesn't auto instantiate

I presume its possible to inherit a class from another library class (I think this is what the ILI9341 lib does with the graphics lib)

But I don't see any problems with adding a new function to the existing class

The only issue with the existing class is that it does the Auto Instantiation, which wastes ram if you are not actually using SPI1

I've already come across the same auto instantiation issue with the Wire library. I needed slow the I2C transfer down to communicate with the OV7670 camera, so I had to instantiate another copy of the Wire library, but passing the slow speed param into the constructor (as fast is the default)
(umm thinking about it, I'm not sure if there is a call to set the speed, but I dont think so... I will need to check)

Having to instantiate 2 copies (one auto instantiated) wasted a few hundred bytes of ram, which isn't ideal, but I can live with it.

Personally I'd have preferred if all the libs didn't auto instantiate , as I'm far more used to doing something like this every time I need an instance of a library object

Wire myWire = new Wire(FLAST_SPEED);

But I think that if we changed this for the SPI library, lots of people would complain that existing examples and libraries that used SPI no longer worked ;-(

PS. Looks like my workload is dropping off, as I've just finished a website and also just submitted an App to Apple for review (so fingers crossed it doesnt get rejected for some bizarre reason ;-) )

So I may be able to get back to looking at all this lovely new code later today or tomorrow :-)
Freelance developer and IT consultant


Mar 25, 2015, 01:02 am Last Edit: Mar 25, 2015, 01:24 am by victor_pv
If I understand it right, the old libmaple HardwareSPI did not autoinstantiate, but the Arduino SPI class does, and that is why the SPI in Roger's repo does too.

Regarding the DMA channels, that can not just be selected at will, they are hardwired in the STM32F103. SPI1 TX can only use channel 3, and SPI1 RX can only use channel 2.
The same channels can be used for other peripherals, but the same peripherals can not use other channels.

We can pass the SPI port as a paremeter (1 or 2), and have the library pick the correct channels accordingly. I counted on having that feature, so spi1 can be used with DMA for a display at the very same time spi2 can be reading from an SD cards, and the sketch can be doing something different.

To have SPI not instantiate, can't we just still use the libmaple hardwareSpi, or is that broken currently?

To add some clarification, currently libmaple includes 2 different methods for setting up DMA transfers. One called DMA tubes, and the other just DMA channels. You can provide a bunch of different paremeters (device address, dma channel, starting memory address, memory auto increment, peripheral address autoincrement, priority, ISR triggers, a pointer to an isr routine). They are great and very flexible, and that is how DMA is done right now in the ILI_DUE library adapted to STM, the normal ILI9341 adapted to STM but with DMA added, and the new SdFat library, which has optimizations for STM32F1, Teensy, and Due. But it happens that we are repeating the code over and over. I'm mostly copy-pasting and changing a couple of things to adapt to whatever library, but it results with each library repeating the code, and also because I currently use the dma channel ISR to signal the end of the transfer, those libraries can not be used at the same time, as each would try to set it's own ISR.
So Roger had the idea, and I agree, that would make more sense to integrate that part in the SPI library, rather that on each device's library, so that way the functions are written once, there is only one ISR, and the sketch or the device libraries just calls the transfers with the parameters needed, without having to know how the whole DMA works in the STM32F1.



I think the old HardwareSPI class is now out of date. I made a copy of it ages ago and did some initial work to make it function in an Arduino way
Since then there have been several updates to the class (by Tim S)

There is nothing stopping us, however from updating the old Hardware SPI class with the new changes

However apart from the auto instantiation, we'd be better off just updating the SPI class to support multiple channels

Yes. each SPI device has a specific DMA channel it works with (and only with), so we'd need to put a switch statement into the code to handle this, but its not a big deal
Freelance developer and IT consultant


Mar 25, 2015, 02:35 am Last Edit: Mar 25, 2015, 03:00 am by mrburnette
However apart from the auto instantiation, we'd be better off just updating the SPI class to support multiple channels
So, we have an architectural question:  
Im inclined to Vote for updating DMA class to support advanced parameters.  I also think an environmental could be set to avoid auto-instantiation*... an advanced feature normally commented but can be activated by advanced users.  This could be used to gain those few hundred bytes of SRAM.

* unless a rule can be set to not link the DMA if not utilized.  I am not too familiar with GCC linker.

My orig suggestion was to sub-class and enhance by overloading, but parameters work, too.  I was not as clear as i could have been when i used the term 'new'.

Otherwise, i do not have any concerns on how the enhancements are glued together.



Mar 25, 2015, 03:08 am Last Edit: Mar 25, 2015, 03:13 am by victor_pv
I vote for whichever solution is more compatible with the main Arduino SPI library.

I am really new to C programming, barely grasping how classes work, so I'm not the one to push for a separate library or expanding SPI, and to decide if autoinstatiate is better or not.

But I do think that leaflabs, with libmaple going away from the Arduino ways in many things, made it more difficult for other people to pick and continue  after they stopped developing it.

Does the DUE has any kind of DMA SPI library, or is just doing it like us configuring the DMA channels like it could be done for any other device? The new SdFat library does it all manually setting registers, but I don't know if that is just for speed, or it's because the DUE does not provide any other means.

EDIT: by the way Brian added the STM32F1 code to the master repo for the SdFat library. I re-synched my repo as he said he had to change a few lines for some google code tool to like it.


Ray and Victor

I'm not sure if its just the terminology, but the DMA code is not a class, its just a series of functions.

These functions can be used within the SPI library etc by including libmaple by including libmaple/dma.h

I'd need to check, but often subclassing makes the subclass a bit bigger than the same code with the additional classes being added to the parent class

So I'd vote for having a #define to prevent automatic instantiation, and add the new method ( function ) to the existing SPI class.

Freelance developer and IT consultant


Mar 25, 2015, 04:18 am Last Edit: Mar 25, 2015, 04:24 am by victor_pv
Yeah current DMA is just a collection of function that set registers in the mcu to setup the transfer. I think I understand what a class is, I just don't know all the stuff that is needed to define one, and subclasses, and inheritance and that stuff, but so far if I don't see the :: in the function name, I basically understand is not a class and I can call it by its name. I hope I'm right ;)

The only thing I am including in the drivers library that I guess takes space every time are:
1.- The ISR functions.
2.- One bolean for each of those (one for TX and one for RX), that is sets to false once the DMA is finished.

The ISRs are pretty short. They disable the DMA channel, so some other device can use it if needed, and then set the Boolean to false. That's it.

I don't know how much memory they take, but can't be that much. If there is a way that those functions only get in the code if the SPI.DMAtranfer function is called, then great. Otherwise, perhaps conditional compiling for that?

Also, I think we only need the TX ISR function, thinking about it, for RX DMA, TX DMA must always be enabled, because sclk will only output clock during a transmission, so RX DMA should never be setup by itself. Given than RX will only receive as many bytes as TX outputs, as soon as TX is over, RX can be terminated.
So we only need 1 ISR and 1 Boolean, or byte, or whoever type we want to use.

Furthermore, I had problems when I tried to detect the end of transmission by reading the flags, but I think those may have been due to other problems rather than an actual problem with the flags, so we could stop using an ISR, and instead just check the flags. I do like the ISR idea though, could even be used to do a callback as Roger suggested before.


Mar 25, 2015, 07:04 am Last Edit: Mar 25, 2015, 05:17 pm by oric_dan
Victor, thanks for the comments. I think as long as you guys keep in mind that, while you're writing your libraries, that multiple devices should have unfettered access to the SPI buss, then you're ok. The Teensy ST7735 library code is really a mess in this regards. There are at least 3 major problems with the Teensy libraries, in regards SPI buss contention.

In any case - without getting too carried away --> It Works Now! I can talk to both ST7735 LCD and 23LC1024 SPI RAM chips now with the Teensy3.1 board.

You guys have been a big help. The past 2 days I've been looking at the Teensy SPI and ST7735 libraries, and trying to decipher the 50-page section on SPI in the d/s. As luck would have it, Ray posted about his o'scope project today, and I took a look at that. Turns out the ILI9341 LCD code for the STM32 is almost identical to the ST7735 LCD code for the Teensy, other than different register setups for the graphics chips, and except for the radical customizations the Teensy guy did.

So, using the STM32 ILI9341 SPI control code as a template, I rebuilt the Teensy ST7735 library, and the darn thing works the first time I try it. Foo. Now, I can put the OV7670 camera system all back together, and see how it goes. The LCD updates are a bit slower now, but I can work on that, now that the darn thing works at all, :-).

One thing I did discover, and possibly the STM32 chip registers are similar, is the Teensy code sends data to the SPI buss using the following command:

SPI0.PUSHR = c | (pcs_command << 16) | SPI_PUSHR_CTAS(0);

Here, c is the databyte, and variable pcs_command contains a mask to the CS bits to be automatically toggled, in this case both CS and DC. From the d/s:

21-16 PCS[5:0]  Select which PCS signals are to be asserted for the transfer. Refer to the chip configuration chapter for the number of PCS signals used in this MCU.
0 Negate the PCS[.] signal.
1 Assert the PCS[.] signal.

So probably by changing this, plus some other setup stuff, I can manually toggle CS,DC and still use the more efficient SPI register operations. Maybe. In any case, another milestone marker passed, :-).

In any case, I'm following what you guys are doing with the LCD libraries, as I may be able to take advantage for my Teensy project. Thanks.


Victor and Ray

Ok. Sounds like everyone is pretty much in agreement ? about adding SPI.DMATransfer() to the existing library

Albeit we'll need to work out the details of how CS is handled.

I guess we have 2 options

a) Pass in the pin number so that DMATransfer can assert and de-assert as part of the transfer
b) The calling function needs to assert CS before calling DMATransfer, in which case we'd need a callback function pointer to be passed to DMATransfer, so that the calling code can be notified when the transfer is complete (and also that the SPI bus is no longer busy). The callback function, can then de-assert the CS line

I'm not that keen on the DMATransfer code asserting / de-asserting CS, as normally this is done by the code that calls SPI.Transfer()

I just had the thought that the new Transactional SPI stuff may be supposed to handle the CS line, but the only reference I can find is on the Teensy site https://www.pjrc.com/teensy/td_libs_SPI.html

SPI.beginTransaction(SPISettings(clockspeed, MSBFIRST, SPI_MODE0))

Begin using the SPI bus. Normally this is called before asserting the chip select signal. The SPI is configured to use the clock, data order (MSBFIRST or LSBFIRST) and data mode (SPI_MODE0, SPI_MODE1, SPI_MODE2, or SPI_MODE3). The clock speed should be the maximum speed the SPI slave device can accept.

digitalWrite(SSpin, level)

Most SPI devices define a transfer of multiple bytes. You need to write the SS pin before the transfer begins (most chips use LOW during the transfer) and write it again after the last byte, to end the transfer. See below for more SS pin details.


Stop using the SPI bus. Normally this is called after de-asserting the chip select, to allow other libraries to use the SPI bus.

Which seems to suggest that the Transactional stuff is only used to set the spi clock speed etc, and doesnt handle the CS line

So basically, as far as I can see, its not the SPI libs responsibility to assert or de-asset CS, hence the function that calls DMATransfer, needs to be told when the transfer is complete, hence I think we need a callback for this.

i.e option (b) above
Freelance developer and IT consultant

Go Up