STM32, Maple and Maple mini port to IDE 1.5.x

Ok, my first github branch upload for USB_MIDI arduino_STM32: github Total experimentally and only for interested persons! :)

madias: Ok, my first github branch upload for USB_MIDI arduino_STM32: github Total experimentally and only for interested persons! :)

Cool

Thanks for sharing

Are there loads of changes between the main version and this version?

All, I completed some testing the support for the stm32 dma for the new sd-fat library. I sent Bill Greiman a pull request in case he wants to add it to the master repo, but in the meanwhile here it is in case anyone wants to test/use it:

https://github.com/victorpv/SdFat

Some notes: 1.- using a 4kB buffer rather than the 512 default one helps a lot. I get 1.6MB/s write and 2MB/s read with 4K buffer in a class 4 card. 2.- Some cards do not like SPI DIV2 speed much. Run the bench example to test the card first, if it fails, lower the SPI speed to DIV4 or even DIV8. The performance doesn't change that much, the buffer size has a bigger effect. 3.- FAT12 support is disabled by default in that library. I tried to use it but failed, but that was in a really old 8MB card, that wouldn't work in FAT16 correctly either. If you try some combinations that work with FAT12, or perhaps a much lower speed that work with really old cards, let me know. 4.-DMA can be enabled or disabled editing a #define in the top of the STM32 cpp file. I have not tested DMA with 2 devices at the same time. Specially I have not tested SD card DMA at the same time as ILI9341 DMA, but because of the way the functions are written, it would NOT work correctly. Once we add DMA to the SPI library, it should work fine for multiple devices in the same sketch. 5.-In the examples remember to change the CS pin setting AND the SPI speed in the sd.begin (...) call. If you try to set an invalid speed it should automatically go to DIV2, which may not work with some cards, see point 2.

All, I completed some testing the support for the stm32 dma for the new sd-fat library.

victor_pv: Very cool. Thanks, I'll try and get around to trying it soon.

Ray

Ray, I was looking at your oscilloscope example, really nice, and really simple code! You should give it a try with the ILI9341_STM library in Roger's repo, that can do the Hlines and Vlines with DMA and speed up the screen refresh a lot.

I may try it myself, but I'm thinking on what could I use to get a sine wave as I don't have any signal generator. The STM in the Maple Mini does not have a DAC, right?

Thanks for sharing it.

rogerClark:
Victor

Try this one.

Its my hacked version of Rays code and it works for me

Note. see my pins for CS and RESET etc , you may want to change these but at least they are in real STM32 ports / pins, not the Maple mini pin numbers (which I generally avoid)

I got around today to trying Roger’s (et al) Adafruit hacks to the ILI9341 libs which is in the most recent ZIP from Github.

Impressive improvements:

Benchmark			T1 (mS)                T2 (mS) 		(t2 - t1) 		% faster
Screen fill			1,026,635 		716,291 	310,344 		30%
Text				74,910 			46,087 		28,823 			38%
Lines 				702,724 		400,688 	302,036 		43%
Horiz/Vert Lines 		84,359 			57,074 		27,285 			32%
Rectangles (outline) 		54,489 			36,604 		17,885 			33%
Rectangles (filled) 		2,132,392 		1,487,410 	644,982 		30%
Circles (filled) 		344,984 		220,662 	124,322 		36%
Circles (outline) 		306,326 		174,199 	132,127 		43%
Triangles (outline) 		222,948 		127,154 	95,794 			43%
Triangles (filled) 		715,597 		472,077 	243,520 		34%
Rounded rects (outline) 	130,131 		78,591 		51,540 			40%
Rounded rects (filled) 		2,331,405 		1,615,938 	715,467 		31%

victor_pv:
Ray, I was looking at your oscilloscope example, really nice, and really simple code!
You should give it a try with the ILI9341_STM library in Roger’s repo, that can do the Hlines and Vlines with DMA and speed up the screen refresh a lot.

I may try it myself, but I’m thinking on what could I use to get a sine wave as I don’t have any signal generator.
The STM in the Maple Mini does not have a DAC, right?

Thanks for sharing it.

Thanks!

I actually did do that this morning and from a visual perspective, I saw about 25% improvement (based on a common freq from my function gen and the increased waveform displayed via the target display.) That is, I saw more waveform because the loop was running faster.

The code was a rainy-day play. The loop could be much faster without the map() function and I could probably combine the two writes to the screen: the one that writes a vertical line for ‘erase’ and the pixel placement based on input voltage (0 - 3.3). But, I just wanted to use base functions and see what I would get.

It may be useful at this point without enhancements for such things as:

  • AC finder for locating wiring behind walls
  • General 10Hz - 100Hz stuff like:
  • Transistor tester
  • Diode forward voltage tests

Also, I thought the idea was neat because the implementation is so simple (slow) but for use in teaching physics or basic electronics, the under $10 price tag is remarkable. The code crys to be enhanced, however!

Ray
My Projects

PS: An X, Y input for playing with Lissajous curves can be done by using 2 AD inputs. Something like the snippet:

for(uint16_t j = 0; j <= myWidth + 1; j++ )
  {
    //        map(         value, fromLow, fromHigh, toLow,   toHigh)
    signalX = map(analogRead(A0),       0,     1023,     1,    myWidth - 1) ;
    signalY = map(analogRead(A1),       0,     1023,     1,   myHeight - 1) ;
<...>
  }

@mrburnette - That oscilloscope demo is pretty neat. Regarding improvements, you might be interested in this article it hints that it may be possible to squeeze 2MS/s out of the STM32F103 ADC.

This would put your $10 o'scope almost in the territory of a real oscilloscope.

It certainly would outperform some of the of the low end USB scopes you find on ebay and any sound card based ones too.

I appreciate this is only single channel and has no real attenuator, storage and so forth, and I'm not sure how your triggering works, but something like this would be quite usable for low voltage, low frequency stuff. It certainly makes an impressive demo of what these little boards can do.

How would you combine the line clearing and the pixel drawing at once? can it be done in the current library? Sorry if it is an obvious answer, I don't know the library that good, I only looked at the spi transfer pieces to add the dma stuff.

Can the library draw a line with dots in different colors in a single call to a function?

victor_pv: How would you combine the line clearing and the pixel drawing at once? can it be done in the current library? Sorry if it is an obvious answer, I don't know the library that good, I only looked at the spi transfer pieces to add the dma stuff.

Can the library draw a line with dots in different colors in a single call to a function?

The Adafruit_GFX is the abstraction. Functions can be modified, added, deleted... or combined.

Every statement such as TFT.drawPixel(j, signalY, ILI9341_YELLOW) ; can have a color as the optional argument. The functions in Ladyada's library are fairly simple IMO.

@mrburnette - That oscilloscope demo is pretty neat. Regarding improvements, you might be interested in this article it hints that it may be possible to squeeze 2MS/s out of the STM32F103 ADC.

This would put your $10 o'scope almost in the territory of a real oscilloscope.

@ahull, I actually have seen that article.

Triggering is not currently performed, I have the signal split to my Rigo storage scope and I'm doing waveform capture for frequency. Over on the function generator, the fine-tune is used for stabilizing the display. This was never intended to be a fancy project, just a few lines of code to follow the AC waveform (w/ DC bias for horiz centering) to be displayed.

One would never consider such a bit-banged implementation on 16 MHz AVR, but at 72 MHz, one can do the unthinkable (or non-recommended) thing just to prove it can be done.

Ray

I just wanted to make a comment about SPI buss contention.

I've had a lot of trouble with this in the past with Rduinos, as some of the 3rd party libraries don't properly release the SPI buss after using it. However, with AVR, it's usually [u]easy[/u] to fix, by simply adding a patch to guarantee that all device CS lines are pulled high before any device tries to use the SPI buss.

However, I am proceeding to get the OV7670 camera system working with my Teensy3.1 board [ARM processor]. It is all working fine with the mega1284 chip now [OV7670, SPI RAM, and ST7735 1.8" SPI Color LCD], but it's very slow.

On switching over to the Teensy3.1 however, there are "extremely" serious SPI buss contention problems. The Teensy guy has pushed the ST7735 library [a patched version of Adafruit_ST7735] so far towards [u]speed-optimization[/u] that it won't allow my SPI RAM chips to play on the same buss [T3.1 only has 1 SPI port]. So, I am currently reworking the SPI libraries that he patched for the ARM chip.

Clearly, the Teensy guy is a one-man army and appears to be completely overloaded, but here you're all working as a big team - luckily. So my suggestion is that while you guys are developing and optimizing SPI code using interrupts, DMA, etc for fast ILI9341 and ST7735 display updates, that you also pay "special attention" to allowing other devices to use the same SPI buss when it's their turn.

So far with the T3.1, the only way I can see to do this is to completely undo the SPI peripheral setup back to the reset condition when the SPI RAM chips use the buss, and then reconfigure it again to the optimized setup to use the LCD. Big PITA. Once you lock in FIFO loading, interrupts, and automatic toggling of CS,DC lines, you're kind of stuck. I imagine I'll have to use double-buffering of the data ....

OV7670 image data [256KB] -> SPI RAM -> smallish ARM RAM-buffer -> LCD

Back and forth, back and forth SPI reconfiguration, with the last 3 steps repeated in a loop. And I'm sure I'll have an even worse problem when I try the ILI9341 LCD.

Even in the Rduino world, people are burned by this problem every day, but it's a lot worse here.

EDIT: A further note - the Teensy libraries have next to zero useful commenting, so it's a trial to figure out what many functions are supposed to even do. I hope you guys do better commenting, since this whole thing is for the wider dissemination.

Very cool, Ray, I like your o’scope. What’s the highest signal frequency you can sample? I did something like this a few years ago, using a Scenix SX-28 chip. Here’s some additional play items:

  • add an x-y amplitude-time grid to the screen

  • do an FFT - then it really gets interesting [I suggest fixed-point rather than float]

  • add a trigger plus ETS [equivalent-time sampling] - then you can display signals
    that are 10X faster than with direct sampling, and now it’s really interesting.

madias: @bigplik: The behavior sounds a little bit "faulty" to me. Sadly, there are almost no people in this thread with an "original maple" (but I guess this device is not original). I use the STM32F103RB only on my nucleo board, with ST-Link V2.1 as upload management. If you wont get a ultimate hint here or you trash the board, maybe invest into a cheapo ST-Link v2 adapter from ali or ebay --3 EUR-- and try to upload it with that (or even re- up the bootloader with the ST-link). Ok, one question: Which board do you choose for the "big maple" - "leaflabs Maple rev 3+ to flash"?

@madias thanks for advice madias, I will buy that programmer ;), yes I have a clone of maple board I am afraid, don't know how, but I managed to upload sketch through mapleIDE and windowsXP, it was connecting and disconnecting from usb port like a crazy and then let me to upload the code, next port wasn't visible and follow that was visible again, it's like a bit of random behaviour I can't predict, however this maplemini another board I have do not make any problems when uploading codes

"big maple" I mean maple rev+5 ;)

@roger I've installed drivers as you wrote, under XP i just show the direction for dfu and serial drivers for device manager in windows. Linux still waiting for drivers ;) I'll check usb socket

@all anyone knows some libraries for OLED or LCD TFT displays for arduinoIDE suitable for STM32? or maybe other way to use eg. Adafruit code like SSD1306 for mapleIDE?

@all

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

https://github.com/BestU/eDuino

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

http://bestni.com/en/Products/Open%20Hadrware/eDuino%20UNO.html

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.

@ray

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 ;-)

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.

@matthias

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

just for relaxing:
youtube - I should not take smartphone videos for presentation :slight_smile:
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!

victor_pv:
<…> 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.

Ray

Ray

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 :-)