Go Down

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

rogerClark

Guys

I have had some success and some problems with SPICLass:DMATransfer

I do have it working, however its via a hack


I'm not sure why this is happening, but if I declare

Code: [Select]
SPIClass
{
public
volatile static bool dma1_ch3_Active;

}

The cpp code is unable to access SPIClass::dma1_ch3_Active 

i.e I get a compile error

I'm really not sure why I'm getting compile warnings with this

even if its non volatile e.g


Code: [Select]
SPIClass
{
public
static bool dma1_ch3_Active;

}


I still get the same compile warnings and the code crashes

So to get it working I've had to make it into a global variable


I guess I'll need to post another question to the programming forum, as I don't understand why the code can't do this :-(

e.g. This article seems to suggest it is possible

http://www.learncpp.com/cpp-tutorial/811-static-member-variables/





Freelance developer and IT consultant
www.rogerclark.net

bigplik

When you went here and downloaded my ZIP, it contained all the necessary libraries- modified for the Maple mini or 328'ish Arduino.  You need to have everything in your sketch folder.


Ray


@mrburnette
I put all that files from your zip package into one folder,
still not working and have same error

mrburnette

#2072
Mar 30, 2015, 12:43 am Last Edit: Mar 30, 2015, 01:01 am by mrburnette
@mrburnette
I put all that files from your zip package into one folder,
still not working and have same error
Are you on Windows, Win7 or higher?  
#include can be written as
#include "./filename.h" OR #include ".\filename.h" but under Linux/iOS you most likely can use only "./filename.h"

Anyway, just remove the dot-slash and just specify the filename as
#include "filename.h"
and see If that works for you.

In the future, please ask for help in the thread STM32 "for the rest of us" here.  This thread is geared more to those testing and modifying the STM core.  Thank you for understanding.

Ray

mrburnette

Quote
So to get it working I've had to make it into a global variable
@Roger,

I had a similar experience with my GPS Clock code.  In 1.0.5, i could have a local array for the bitmap, but in 1.5.6, i had to make it a global.  Made no sense then or now.

Ray

rogerClark

#2074
Mar 30, 2015, 01:14 am Last Edit: Mar 30, 2015, 02:08 am by rogerClark
Quote
I had a similar experience with my GPS Clock code.  In 1.0.5, i could have a local array for the bitmap, but in 1.5.6, i had to make it a global.  Made no sense then or now.

Ray
I'll post a question to the programming section

Perhaps those clever guys can explain ;-)

Edit

OK.

It looks like I didn't understand how C++ needs to have this written

This code compiles (not sure if it runs but I suspect it would)

Code: [Select]


class MyClass
{
public:
static volatile bool testStaticVar;

void TestStaticVariable();
};

void MyClass::TestStaticVariable()
{
MyClass::testStaticVar=false;
}

MyClass theClass;// Instantiate mn instance of MyClass

volatile bool MyClass::testStaticVar=false;

void setup() {
  // put your setup code here, to run once:
theClass.TestStaticVariable();
}

void loop() {
  // put your main code here, to run repeatedly:

}



the important thing is that the static var seems to need to be declared again outside of the class.

Its as if the class structure is just reserving a space for this var


I don't normally program in C++ , and in other languages e.g C# or Java etc etc, the declaration e.g. in the header is enough to tell the compilor to reserve space etc for the var, but this doesnt seem to be the case with C++
Freelance developer and IT consultant
www.rogerclark.net

rogerClark

@all

I've done a first pass at taking Victor's code and convert it for use in SPI

I'm not sure if its currently reading back, it may only be writing to SPI, but the DMATransfer function is now working, and I'm using it in the normal ILI9341 lib for fillrect

I've only written the synchronous version at the moment


Its been somewhat more complicated than I'd expected with 2 issues in C++ with the ISR callback needing to be a static member of SPIClass and also I've had to declare a global for the dma_active flag

We may be able to improve the dma_active thing to make it a static var of the SPIClass but I can't get it to compile at the moment if I do that :-(

I'll check later whether its reading the data or just writing to SPI (possibly only writing, as only the write channel has been setup for the DMA)

But its some progress 
Freelance developer and IT consultant
www.rogerclark.net

victor_pv

@Roger I think using a single buffer should work fine as TX DMA will move a byte and increase its buffer address counter at the start of the transfer, while RX DMA should write to at the end of the byte transfer, but make sure the RX buffer register is cleared at the end, otherwise and incoming byte waiting in the RX buffer register may get written to the RX buffer address right away at the start.
That is something that is done in the sdfat library DMA for the Due, even though it uses a different buffer for TX and RX, and I had to do it for the STM, but I believe I did not include it in the ILI_STM library files. It is included in the official sdfat repo, in the stm32 cpp.

Besides that, I believe it's probably more flexible to be able to set both independently, and whenever you want just pass the same pointer for both.

About the ISR, I'm curious to see how you resolved the callback.
The best way I could imagine was like this:
Have a pointer called say DMACallback.
Set that pointer to a function within the library by default.
Set the ISR to call the function in that variable, DMACallback, in every case.
If the DMATransfer call provides a Callback pointer, change the value of DMACallback to call that.
That way the ISR always will call whatever DMACallback points to, with no if within the ISR, and the library implementation of the callback could be just setting a Boolean to true or false, that the DMATransfer function can check when it need to block until the transfer is complete.
I hope I explained it clear, I think I have it clearer in my mind than I can explain.

I couldn't think on any other easy solution.

Regarding the global variable, I had the same issues, I couldn't figure a way to get it to compile and to be used in the ISR successfully unless I made it global. And I had to set the ISR a static outside of the class, otherwise I would get some errors.

Did you put the code in the repo or somewhere else? I can modify the sdfat library to use it and test with an sdcard as that will involve reads and writes, and I can even get some performance tests done.

rogerClark

Victor

Re: Callback functions

I will always get the DMA to call the internal function inside the SPI class first, then inside that callback, I was going to call the user supplied function, after the transfer had finished e.g something like this

Code: [Select]

static inline void DMA1_CH3_Event() {
dma1_ch3_Active = 0;
dma_disable(DMA1, DMA_CH3);

                if (userCallBackDMA1 != null) {

               userCallbackDMA1(); // call user supplied function
               }
}


We will have to declare a static variable for each user callback per DMA channel / SPI channel, as DMA1_CH3_Event had to be declared as a static function / method in the class, because C++ doesn't allow you to resolve a class method to a function pointer, as static functions can't access instance data unless they are passed a pointer to the instance (and we can't do this because DMA1_CH3_Event is called with no params via the processor.



Re: SPI Read

I'm pretty sure this is not working with my current DMATransfer code, as I just took your code that sends data to the ILI9341 and generally just copied bits of it into the SPI class.

So I'll need to go back to the original example code on the leaflabs forum and grab the DMA read code


Re: 2 buffer pointers

Yes. I totally agree, will change the code, so that its SPIClass::DMATransfer(byte *transmitBuf, byte *receiveBuf, int length)

as the user can always just pass the came pointer to both buffers if they want

I will try to finish those changes today

PS. I have pushed the first version of DMATransfer and my changes to the ILI9341 lib to the repo, so they should be visible

PS. I did look at using DMATransfer for other operations in the ILI9341 lib, apart from fillrect, but most things end up being slower, because the time to setup the buffer or 4 or less bytes takes longer than just sending the bytes one by one


Freelance developer and IT consultant
www.rogerclark.net

rogerClark

#2078
Mar 30, 2015, 08:33 am Last Edit: Mar 30, 2015, 08:49 am by rogerClark
Hi Victor,

I'm not sure what you mean when you say

Quote
but make sure the RX buffer register is cleared at the end, otherwise and incoming byte waiting in the RX buffer register may get written to the RX buffer address right away at the start.
Also.

I have done some tests and ...

If I use the same buffer to do fillrect I have a problem because the buffer gets overwritten with the rx data. I could use memset to copy a new buffer, but that is a waste of CPU time, so I am now using an separate tx and rx buffer

However it makes more sense to add DMAWrite and DMARead functions for just writing and just reading I think

I could put code into DMATransfer to check for rx or tx buffer are not null pointers, but that would slown down the setup of the DMA

So I think DMATransfer should do tx and rx and I will add 2 more functions.


Edit.


OK.
Pushed a new version, that uses separate TX and RX buffers, I also wait for RX DMA to complete before checking for TX to be complete and also for SPI to not be busy before returning.

This seems to work fine in the ILI9341 lib for fillrect etc.

However I have not tested it with anything which actually reads data.

I will need to look at Victor's SD code (did you post it ??)

Thanks

Roger
Freelance developer and IT consultant
www.rogerclark.net

mrburnette

Quote
Pushed a new version, that uses separate TX and RX buffers, I also wait for RX DMA to complete before checking for TX to be complete and also for SPI to not be busy before returning.

This seems to work fine in the ILI9341 lib for fillrect etc.
+1
I'll try and give it a go today or tomorrow.


Ray

victor_pv

Roger, my DMA RX code that was working fine is in the sdfat library, in this file:

https://github.com/greiman/SdFat/blob/master/SdFat/SdSpiSTM32F1.cpp

That one is tested to work with a bunch of SDcard tests, reading and writing.

Regarding checking for RX DMA to be over, I dont think it is necessary given the fact that RX can only occur while TX is going on, because the sclk only outputs clock on TX. If TX is finished, RX will not receive anything else as there no clock. I think it should be disabled, rather than possibly hanging there waiting for bytes that will not come in because there is no clock.

I understand there is no clock if TX is not going on from something I read before about the F103 SPI. If I'm wrong let me know.

I'll pull the code from your repo when I get home and run a test with an SD card that was working fine 100% of the time with dma. I can even compare performance to let you know if it is dropping below normal for any reason.

rogerClark

Victor

Thanks

I will take a look at your code.

Unfortunately my SD test rig wasn't working the last time I tried it:-(

I find that if I leave the SD card in the adaptor, and then do general testing with SPI e.g to ILI9341, that somehow the card can get corrupted and I need to reformat it on my PC

This may not be what happened in this case, I may have a loose wire.
But its probably going to take a while just to get the old SD card example working :-(
Freelance developer and IT consultant
www.rogerclark.net

rogerClark

#2082
Mar 30, 2015, 11:40 pm Last Edit: Mar 30, 2015, 11:53 pm by rogerClark
 Hey guys

Has anyone noticed the new Boards Manager feature in 1.6.2

It seems to just like AVR and SAM based Arduino boards and I can't see an "Add" button

Any ideas of how this works ?

Edit

Interesting

They have changed the whole way they install the hardware folder

Due is not installed by default, only AVR is,and AVR I suspect is unpacked on installation

Take a look in C:\Program Files (x86)\Arduino\dist  if you have 1.6.2



Ummm.

This could be serious

1.6.2 seems to work for me, (out of the box) but looking at the boards manager, Due was not installed, so I'm not sure where the IDE was looking for the ARM compiler, as its not in the hardware folder any more

I'm just "Installing" the Due board (as I have a Due) and I'll see where the compiler is running from by looking in verbose mode

arrggghhh

Strange I didnt notice any of this stuff in the developers group mailing list, perhaps I need to subscribe to something else

Freelance developer and IT consultant
www.rogerclark.net

rogerClark

#2083
Mar 30, 2015, 11:55 pm Last Edit: Mar 31, 2015, 12:05 am by rogerClark
Do not use 1.6.2

Latest version of 1.6.2 does not package the ARM compilor in the same location as previous versions

So my repo no longer works.

Arrggg!

I will investigate and report back


Edit

They have decided to hide it all away in the APPData folder

C:\Users\rclark\AppData\Roaming\Arduino15\packages\arduino\tools\arm-none-eabi-gcc\4.8.3-2014q1/bin/arm-none-eabi-g++


On windows to see where they've put stuff

Go to the search box by the Start button and type

%Appdata%/Arduino15


It will open a window

all the files are now in here

Edit.

I can fix it for 1.6.2 but will need to give instructions that Due needs to be downloaded, or I will have to put the Arm compilor in my repo

new recipe path is

{runtime.tools.arm-none-eabi-gcc.path}/bin/

Freelance developer and IT consultant
www.rogerclark.net

ahull

#2084
Mar 31, 2015, 12:41 am Last Edit: Mar 31, 2015, 01:06 am by ahull
FWIW under Linux the nightly build of the 32bit IDE puts the compiler in...

/home/{username}/.arduino15/packages/arduino/tools/...

For example

/home/andrew/.arduino15/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-none-eabi-gcc

so somewhere it must define that $HOME/.arduino15/packages/arduino/tools/...
Not sure why .arduino15 when we are on IDE 1.6.x ... nor am I sure what the purpose of all this is... but what I will say is that the first time installed on this machine, it broke spectacularly and I had to delete the /home/andrew/.arduino15 folder and try again.

Worked the 2nd time though.

Go Up