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

Ray, I agree it should be compatible with old code, I think that should be the 1st concern.
If we add a new DMA transfer function, with a new name such as SPI.DMATransfer (), it should not interfere at all with previous code that doesn't use it.

About the callback, I believe it should be easy to implement with the ISR.

I propose something like this:
1 TX SPI.DMATXTransfer (*char src, uint16_t n bytes, *callback pointer OR optional CS to toggle before return); any returned byte is dropped.

1 RX SPI.DMARXTransfer (*char dst, *char src OR byte (where byte is to be sent over and over for n times), uint16_t n bytes, *callback pointer OR optional CS to toggle before return);

Internally, it if the user pass a callback pointer, it sets the ISR to call that callback on interrupt, fires the transfer, returns right away and will notify with the callback. If the user instead pass a CS to toggle, it sets the ISR to call a callback defined within the library to toggle the pin for the user. If the CS is passed as a parameter, it does not return until transfer is over.

My logic on that is, if the user does not need to do other stuff while the DMA is going on, it simplifies the use of the library, specially for new users. We can even remove the CS toggling from here altogether, and have the callback pointer as optional. If not passed as parameter, it will use it's own and block until complete transfer.
If the user wants to use the callback, then I think CS is better managed outside the DMATransfer function.

Just for reference, this is how it is done in the SdFat and the ILI_due libraries right now. The structure is copied from how they had it set up in the due, it could be simplified more:
https://github.com/greiman/SdFat/blob/master/SdFat/SdSpiSTM32F1.cpp

One more note, why I want to pass 2 pointers to the RX function with a buffer to send?
Imagine you need to send 4 bytes with a command, and receive 512.
Instead of setting a 4 bytes DMATX, and then a 512 DMARX sending blanks, you could set up a 516 bytes transfer. In the TX buffer write your 4 commands at the start of the buffer and fill blank the rest. The receive buffer 516 bytes long too. Then you fire a RX that will transmit 4 bytes with your command, and receive 4 empty responses to those 4, and the 512 bytes that you were expecting. With a single DMA setup you sent the command and received the data.
Given that I think buffers should be setup once with their maximum size and just used over and over, I don't see a problem wasting a bit of memory. You can even setup multiple command, blanks n bytes, command, black n bytes if you know you will need to do those 2 transmissions in sequence in advance. If you don't want to use the feature, just send the commands by yourself, and set the RX to just send 00 or FF over and over, doesn't need a buffer to do that.

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 SPI Arduino Library, connecting SPI devices to Teensy

Roger, I looked at that stuff on Monday when I was having my Teensy SPI RAM vs ST7735 buss contention problems. Unfortunately, it didn't do much for me. Here's the problem, you can look at the source on this page - note that SPI.h has about 4X as much "source code" in it as does SPI.cpp, ummm. Also, note the different sections for AVR, Teensy, etc.

He wrote some code here, for SPI setup and transfers, but then he overwrote it in the ST7735 library, so this stuff no longer seems effective - or work. I'm not quite sure.

	// Before using SPI.transfer() or asserting chip select pins,
	// this function is used to gain exclusive access to the SPI bus
	// and configure the correct settings.
	inline static void beginTransaction(SPISettings settings) {
		if (interruptMasksUsed) {
			__disable_irq();
			if (interruptMasksUsed & 0x01) {
				interruptSave[0] = NVIC_ICER0 & interruptMask[0];
				NVIC_ICER0 = interruptSave[0];
			}
			#if NVIC_NUM_INTERRUPTS > 32
			if (interruptMasksUsed & 0x02) {
				interruptSave[1] = NVIC_ICER1 & interruptMask[1];
				NVIC_ICER1 = interruptSave[1];
			}
			#endif
			#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
			if (interruptMasksUsed & 0x04) {
				interruptSave[2] = NVIC_ICER2 & interruptMask[2];
				NVIC_ICER2 = interruptSave[2];
			}
			#endif
			#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
			if (interruptMasksUsed & 0x08) {
				interruptSave[3] = NVIC_ICER3 & interruptMask[3];
				NVIC_ICER3 = interruptSave[3];
			}
			#endif
			__enable_irq();
		}
		#ifdef SPI_TRANSACTION_MISMATCH_LED
		if (inTransactionFlag) {
			pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
			digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
		}
		inTransactionFlag = 1;
		#endif
		if (SPI0_CTAR0 != settings.ctar) {
			SPI0_MCR = SPI_MCR_MDIS | SPI_MCR_HALT | SPI_MCR_PCSIS(0x1F);
			SPI0_CTAR0 = settings.ctar;
			SPI0_CTAR1 = settings.ctar| SPI_CTAR_FMSZ(8);
			SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_PCSIS(0x1F);
		}
	}

	// Write to the SPI bus (MOSI pin) and also receive (MISO pin)
	inline static uint8_t transfer(uint8_t data) {
		SPI0_SR = SPI_SR_TCF;
		SPI0_PUSHR = data;
		while (!(SPI0_SR & SPI_SR_TCF)) ; // wait
		return SPI0_POPR;
	}
	inline static uint8_t transfer16(uint16_t data) {
		SPI0_SR = SPI_SR_TCF;
		SPI0_PUSHR = data | SPI_PUSHR_CTAS(1);
		while (!(SPI0_SR & SPI_SR_TCF)) ; // wait
		return SPI0_POPR;
	}
	inline static void transfer(void *buf, size_t count) {
		if (count == 0) return;
		uint8_t *p = (uint8_t *)buf;
		SPDR = *p;
		while (--count > 0) {
			uint8_t out = *(p + 1);
			while (!(SPSR & _BV(SPIF))) ;
			uint8_t in = SPDR;
			SPDR = out;
			*p++ = in;
		}
		while (!(SPSR & _BV(SPIF))) ;
		*p = SPDR;
	}

	// After performing a group of transfers and releasing the chip select
	// signal, this function allows others to access the SPI bus
	inline static void endTransaction(void) {
		#ifdef SPI_TRANSACTION_MISMATCH_LED
		if (!inTransactionFlag) {
			pinMode(SPI_TRANSACTION_MISMATCH_LED, OUTPUT);
			digitalWrite(SPI_TRANSACTION_MISMATCH_LED, HIGH);
		}
		inTransactionFlag = 0;
		#endif
		if (interruptMasksUsed) {
			if (interruptMasksUsed & 0x01) {
				NVIC_ISER0 = interruptSave[0];
			}
			#if NVIC_NUM_INTERRUPTS > 32
			if (interruptMasksUsed & 0x02) {
				NVIC_ISER1 = interruptSave[1];
			}
			#endif
			#if NVIC_NUM_INTERRUPTS > 64 && defined(NVIC_ISER2)
			if (interruptMasksUsed & 0x04) {
				NVIC_ISER2 = interruptSave[2];
			}
			#endif
			#if NVIC_NUM_INTERRUPTS > 96 && defined(NVIC_ISER3)
			if (interruptMasksUsed & 0x08) {
				NVIC_ISER3 = interruptSave[3];
			}
			#endif
		}
	}

You'll notice that in beginTransaction(SPISettings settings), settings only deals with basic SPI aspects like bitrate, mode, data order. Then, you'll notice that endTransaction(void) only deals with possible interrupts having been used, and nothing about SPI setups. There is nothing in here to deal with the ST7735 library having overwritten the setups to use automatic CS activations, etc. So, he has

SPI0_PUSHR = data; here, but he has

SPI0.PUSHR = c | (pcs_data << 16) | SPI_PUSHR_CTAS(0); in the ST7735 library, as mentioned yesterday.

I'm not certain whether the effects of using this last statement actually "release" the SPI buss properly, but it doesn't seem to in my program, as mentioned yesterday.

On and on - however, you can probably use the basic transaction idea, but just straighten things out better, and don't have your "optimized" SPI LCD libraries screwing everything up.

Adafruit_SSD1306_STM32 library
Hello,
today my 128x64 I2c Oled's arrived (haitec.cn).
I've done successfully a port of the adafruit_SSD1306 library and called it Adafruit_SSD1306_STM32 (it's not compatible with avr/sam anymore, I have not the time for such gadgets)
Some things to know:
Only I2c is tested! I've done the typdef conversation for SPI, compiles ok, but I cannot test it!
This adaption uses hardware I2C (hardwire.h), instead of "wire.h" (I hate the software bitbang digitalWrite mess up thing)
Port: I2c2. SDA=0, SCL=1 on maple mini
To change it to Port I2C1: (*.cpp file on the top)
//HardWire HWIRE(1,I2C_FAST_MODE); // I2c1
HardWire HWIRE(2,I2C_FAST_MODE); // I2c2

Don't forget to setup the correct I2c address in your code! With my display:
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

Adafruit_SSD1306_STM32.zip (25.1 KB)

All I can say is ... YES! The darn thing is finally working end-to-end on the Teensy 3.1 board.

I put the OV7670 system all back together, and used the new ST7735 library that I patched yesterday, and am finally getting good image captures to SPI RAM.

OV7670 image -> SPI-RAM -> ST7735 LCD display

Getting rid of the LCD SPI optimizations fixed it, so the 23LC1024 RAM can now get onto the SPI buss properly.

Roger, here are a couple of points you might take note of.

  1. using the regular SPI.transfer function to capture OV7670 data is too "slow" for 24 and 48-MHz
    T3.1 clock speeds, but it works fine at 72 and 96-MHz.

I was getting images displayed as 4/ea 80x60 blocks on the LCD for the slower T3.1 clock speeds, which indicates each run though the capture loop was missing 1/2 the data. The higher clocking fixed this.

  1. besides adding an hsync before each capture, as I mentioned previously, I also played with
    having the PCLK sync both ways shown below, as having it the wrong way produces hash;
    this is obviously tied up with how fast the code is going.
      wait_pclk_high();   // get hi-byte;
      SPI.transfer( (uint8_t)(GPIOD_PDIR & 0xFF) );
      wait_pclk_low();

-VERSUS-
      wait_pclk_low();   // get hi-byte;
      SPI.transfer( (uint8_t)(GPIOD_PDIR & 0xFF) );
      wait_pclk_high();

Amazingly, right now the captures with 96-MHz T3.1 are no faster than with the mega1284 board, so next to try some speedup measures, and also move over to the ILI9341 320x240 LCD. Whew!

Ray and Victor

I think we are all in agreement.

Adding 2 new functions to the SPI class will not have any issues for old code

Normally the compiler doesn't link in functions that are not used but with libmaple it may be linking all functions because of the whold_archive flag. I will check if adding a new function to SPI makes it bigger

@victor, I see what you mean about one function that doesn't return until the transfer is complete, which saves needing to write a callback function, and can be used if you only have one think you want to transfer quickly and don't need it to run Asynchronously.

And another function that returns straight away and then calls back on completion.
Both functions internally to the SPI lib need to use the ISR callback, its just that on the Asynchronous call, that the ISR calls the callback when its finished.

@ray

I don't think I explained things very well about my thoughts on begintransfer()

I totally agree it just changes the settings.

I'm not sure why the transaction system was added really, when the same effect could be achieved by calling set divider and set bit order.

Dan

Ok. So you are transferring to SPI RAM straight away. As Pclock is only around 1 MHz , it should be possible to transfer to SPI at that rate, ie you'd need SPI speed set as fast as possible, as its going to take at least 16 cycles per byte using DIV2

I will try to get back to my ov7670 test rig and read the low res image straight into internal ram, and then I will need to write code to rotate and then write to the LCD, as the ILI9341 display I have is portrait but the camera is landscape

the ILI9341 display I have is portrait but the camera is landscape

Roger, both LCD libraries have a set-rotation function.

The Teensy sets the SPI clock rate in both the SPI and ST7735 libraries, but the commenting is so skimpy, I'm not sure what the values even are. Will have to play with this now that it's all working. I should also be able to step up the PCLK rate by 2X or 4X.

I initially had the image captures going into the internal RAM of the T3.1 chip, and that worked straightaway with no hitches. But you can only store a 160x120 image in there [with 2 bytes/pixel it takes 38KB], so I needed the external SPI RAM to handle 320x200 images for the ILI9341 LCD. The system is now capturing from camera straight to SPI RAM, and outputting from SPI RAM straight to LCD, with no buffering needed inside the T3.1 chip.

BTW, I am still using the mega1284 to configure the OV7670 at startup, and am using the straight unmodified Rduino IDE Wire library, as I mentioned a couple of weeks ago. Wire works fine with the Rduino. Now will play with doing the camera setup in T3.1 code.

Hi Dan

OK re: RAM. I'm using a F103RCT based board, which has 64k ram !!
( http://www.st.com/web/catalog/mmc/FM141/SC1169/SS1031/LN1565/PF164486 ) so there should be enough ram for both the image and the variables in the code. i.e there should be 26k free for vars which should be enough

I'm setting the camera up using the Wire lib on the STM32, which also works OK, but I did have to slow the data rate down to 100kpbs, but I think this is mainly due to my pullup resistor values. If I used lower values I may be able to use the default rate for the library which is 250kbps
(but it could just be that the bus timing for SCCB is not the same as for I2C and its will only every work using the Wire lib when its run slowly)

I was hoping to get some time today to look at this, but I have some bugs to fix for my day job, so I doubt I will be able to look again until the weekend

Yeah, T3.1 also has 64KB internal RAM, so both chips have enough for 160x120x2bytes.

I've been looking at this board. $24 inc LCD, jeez, would be great for directly hooking the OV7670 or other camera.

They mention using the following dev tools, which I think are all expensive. Any chance your guys' disto will work with this board?
http://www.st.com/st-web-ui/static/active/en/resource/technical/document/user_manual/DM00097320.pdf
– IAR Embedded Workbench® for ARM (EWARM) by IAR Systems
– Microcontroller Development Kit for ARM (MDK-ARM) by Keil™
– TrueSTUDIO® by Atollic

@Roger, if you start writing the functions let me know. Otherwise I may have time this weekend to start writing them. About the F103RCT, doesn't that have 48KB?

@Oric, it seems like the STM32F4xx are very different devices than the F1xx. Registers, peripherals, even the core is different as one is Cortex M4 with FPU and the other Cortex M3. There is one other repository for STM/arduino that is adding support for F4xx parts, but not sure if the F427 is supported.
You may want to look at coocox for a free IDE. I have read good things about it, although I have not used it.
Roger found an F103VEZ board, that device has 1MB of flash, and the board even has an eeprom and a spi flash on board for around $15, a display this days is just $4 or 5, so for the same price of the F427 discovery, and an F103VEZ is more likely to use most of the code in this repo with little change, as the cpu core and most peripherals are similar.

There is a link posted in this thread a couple of pages back, have a look at that.

Personally, I got a Nucleo F411 board, I wanted something compatible with mbed to try it out, and that seemed like a good option. I haven't used it yet. In fact I think I haven't compiled anything that needed more than 40kB, so I am still far from filling the maple mini.
I remember the days I programmed pic12 in assembler, with 512 bytes of flash and 20 or so of ram... That was the last thing I programmed until this days with the Arduinos.

Dan Victor

About the F103RCT, doesn't that have 48KB?

Not sure. The spec says, up to 64K but then doesnt seem to mention any other ram sizes, normally ram in a series e.g. the R series is the same, its just the Flash size is bigger in the RE than the RC version

C = 256 Kbytes of Flash memory
D = 384 Kbytes of Flash memory
E = 512 Kbytes of Flash memory

Re: Other board

I have a F103ZET board know, which does have external FLASH ram connected to SPI, but I've not had time to investigate how to use it, and I'd need to disconnect all the wires from the RC board, which I ended up having to solder to the back of the RC board as I didnt have enough push on connector wires for the large number of wires needed to connect the camera (I have since ordered some more wires, so will probably unsolder the camera when those wires arrive and move it to the ZET board)

The VET and ZET boards are a good match for the camera s they are still not hugely expensive i.e less then $20 US and have Flash ram and also an SD card socket (actually it depends which board you get but these things are available)

Re:F11 nucleo

I have an F4 discovery, but have only managed to get the Blink stuff to work with the code thats in the repo. The F4 stuff is an old derivaite of libmaple from well before Bob and I started to bring it up to date with IDE 1.6+

You could try giving it a try with your Nucleo board, but don't expect serial to work, just try blinking, that may work !

Edit.

Victor, I'm hoping to get some free time later today so I will investigate writing those functions and let your know (PS. I'm on UTC +11 currently, so its just after lunch here)

@dan

Use CooCox or Em:Blocks if you want to use STM's own libs

You can get a free copy of Keil, but it has a limit of the max program file size

Also I got bogged down with keil as its modular and I couldnt figure out what modules I needed to install to get it to work with the F103

If you do decide to use Keil, you can use the GCC compilor with it, by changing a a load of settings (there are web pages about how to do this, which I'm sure you can find)

CooCox worked quite nicely for me, as long as you tick the correct boxes to load the correct libs and templates

I think I also had a go at Em:Blocks and it seemed to work, but all I was going was flashing a LED

However the Arduino IDE hides all the messy stuff about setting GPIO, e.g. just pinMode() takes about 20 lines of code to configure a single GPIO pin

and there is a lot of other stuff as well like the RCC and AFRemap stuff that you need to put in, if you are coding from scratch ;-(

@Dan: Also worth a look into: (Didn't here about it till I got a advertisment from ST last week)

should be available for linux and OSX Q2/15

Thanks for the info, guys. I'm pretty much buried with the Teensy, but liked the F4 board due to it's having the LCD built in. Would be easy to hook to the camera directly. Better than having 35 dangling wires.

@victor_pv

I hope you don't mind, but I'd like to re-instate the old - non-dma version of the ILI9341 lib that you zipped up, as it can co-exist with the other DMA versions, and It will be helpful for me to have a version if the lib that I can test with a DMA version of the SPI class

Also, looking at the file name Adafruit_ILI9341_STM versus the class name for Adafruit_ILI9341 , by convention the class name is the same as the file name, so I'm going to change it to match the file name, I'll also change the examples, so that they reference the correct class name.

Note the Due file / class is OK because it uses the class name ILI9341_due and the file name is ILI9341_due.cpp

Thanks

Roger

Edit

I've now made the change and pushed it to the repo.

I've updated all of the examples, and have tested most of them. Actually one or two of the examples don't currently work, because they seem to call functions not in the library, but I'm pretty sure that the problem has not been caused by this change and was probably there before the change.
(though I could be wrong ;0) )

Roger I don't mind at all.
I kept the files zipped for that purpose, in case the non-DMA version was needed again.
About the file name change, I think it should be fine, as that should affect only at the point of instantiating the class, correct? so that would involve just changing 2 lines in the sketches, not a big deal.

About the examples, the ones I tested would have my DC, RST and CS pin definitiong, that were 8 9 and 10, so any example that has those, was one I tested and worked. If it doesn't have those pins, then I did not test it.
I can have a look at the ones not working. Do they work with the non-DMA version of the library?

I think we should freeze further changes to libraries using DMA until we have the new functions in the SPI library anyway, then we can optimize using them.

Just a note, on the due one, I still don't quite understand why the original author included his own copy of some of the sdfat files, with changes in the class names and little more than that. It would make more sense to just require the sdfat libraries to be available and use them.

madias:
Adafruit_SSD1306_STM32 library

Thanks!

I have a different OLED with same resolution: 2-color mono display

I got my OLED working this morning using Software SPI. It's refusing to work using Hardware SPI, but I have no time today to dig into this issue... No issue with Hardware SPI and ILI9341 previously.

I also tried it on Nano328 and it worked using same pin numbers (unmod libs!):

 // software SPI works on Maple Mini ARM 32-bit
  // use these settings for the OLED_Pro smart display...
  // These pin #'s are for Maple Mini/UNO/Nano/Mini328
  #define OLED_DC    6  // D/C
  #define OLED_RESET 5  // RST
  #define OLED_MOSI  4  // SDA
  #define OLED_CLK   3  // SCL
  #define OLED_CS    7  // Not Connected to OLED board
  Adafruit_SSD1306 OLED(OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);

Ray
OLED on the cheap...

IMG810_web.jpg

victor_pv:
Just a note, on the due one, I still don't quite understand why the original author included his own copy of some of the sdfat files, with changes in the class names and little more than that. It would make more sense to just require the sdfat libraries to be available and use them.

Hi Victor,

OK about the Due SDFat stuff. The easiest thing is to just try deleting those files and references to them e.g. includes, and see if it still works just driving the display

I see this quite a lot, where people bundle unused stuff as part of their code, mainly because they have not had time to remove and test it after its removed (which I totally understand, being time poor myself )

Re: Renaming of the file

Its all done now. I had to change the class name in the Adarduit_ILI9341_STM.cpp .h and and update the constructor method names (2 of them) and update the examples in the Adarduit_ILI9341_STM/examples folder
But all the main examples now work fine.

e.g the digital clock and the analog clock and the graphics test and one or two others all work fine.

However one of the examples calls init() which doesn't seem to be in either the ILI or GFX lib. But unfortunately I didn't have time last night to work out why it was calling init() or why it was missing / which class should contain it.
Its quite possible that some of the examples just didnt work in the first place (I also see this quite a lot with libraries, because people update the lib but don't have the time to test all the examples - especially when there are a lot of them)

I agree, there is no point in doing any more work on the ILI etc libs until the SPI DMA stuff is integrated, as we will then be able to remove the DMA stuff from the ILI libs (hopefully)

I've had a bit of a cold this week, which has prevented me from doing as much work on the STM32 stuff as I'd like to have done.

And I must admit, I've been looking at some other gadgets (Bluetooth low evergy beacons aka iBeacons), because I have some possible business opportunities based around those devices.

And I've just noticed that someone has ported the ESP8266 Wifi toolchain and made an Arduino IDE version (similar to the STM32 stuff, but it has to bundle and external compilor as the ESP8266 chipset isn't ARM)

So I'm interested in getting that to work from both a personal and also commercial perspective, as I have some possible business opportunities based around the Internet of Things (IoT)

However, it looks like the weather this weekend, is not going to be especially nice, so I will hopefully have some time to devote to all these desperate projects

Cheers

Roger

Roger, the init() thing is because the author of the GFX_AS library that added more fonts, for some reason renamed begin() to init(), I have no idea why... so as I used your ILI9341 driver as a base to add DMA, I decided it was better for compatibility to leave it as begin() like it use to be, and it was in your driver. I think I tested all the examples, but looks like I forgot to save some in the final folder. Changing init() for begin() should be all that's needed for those.

About the due one, is not that it left so much of the sdfat libraries that is not needed, but rather that renamed some classes, so if you have the complete sdfat library and the due one, I can only imagine a bunch of functions are going to take double the space in memory because they are in two different libraries with a different class name. Same parameters though, so to me, it would make more sense to keep the same class name. Not a big deal, but just a possible waste of space. Anyway let's leave that aside until we have the SPI DMA functions.

EDIT: Found the ESP8266 Arduino IDE, thanks for the heads up!

The ESP is based on MIPS as far as I know.

Hi Victor

RE: ESP8266

http://forum.arduino.cc/index.php?topic=311117.new#new

But unfortunately its not working for me at the moment :frowning:

It seems to compile using the ESP8266 (I agree I think its an Extensia device which is MIPS)

However although it claims to be uploading the bin files to the device, my existing program is not actually being overwritten

I normally use a python tool to upload but the author is using a windows EXE

I'm currently just trying to see if I can get the Python uploader to upload the Arduino builds (literally at this moment in time)

So I'll post again if I get any results !