Go Down

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

mrburnette

Quote
I'm not sure if its just the terminology, but the DMA code is not a class, its just a series of functions.
Well, crap.  I should probably not write in the forum after dinner and 3 beers.

What I was thinking when I posted my flawed logic was along the way that Limor handles her GPS code by capturing SoftwareSerial.  In the case of the Maple-centric SoftwareSerial, it looks like:

Code: [Select]
SoftwareSerial::SoftwareSerial(uint8_t receivePin, uint8_t transmitPin, bool inverse_logic /* = false */)
{
 if (receivePin == 0 && transmitPin == 1) {
 port = &Serial3;
 } else if (receivePin == 8 && transmitPin == 9) {
 port = &Serial2;
 } else if (receivePin == 25 && transmitPin == 26) {
 port = &Serial1;
 } else {
 port = NULL;
 }
}

SoftwareSerial::~SoftwareSerial()
{
 end();
}


Then in my main sketch, I pass the GPS object the address:

Code: [Select]

// create mySerial object for exclusive use by Adafruit_GPS
SoftwareSerial mySerial(0, 1);          // Rx Tx : Connect the GPS TX (transmit) pin 0 (NC on pin1)

Adafruit_GPS GPS(&mySerial);                                      // create GPS object


The user code can detect when the 1st buffer has filled from serial interrupts and move on while the 2nd buffer is being loaded...

Code: [Select]
char c = GPS.read();                                            // read data from the GPS and check for full sentence
  if (GPS.newNMEAreceived()) {
    if (!GPS.parse(GPS.lastNMEA()));                              // sets the newNMEAreceived() flag: return; no longer used
  }
...



But, honestly, sticking in more functionality as functions and implementing a callback is Ok by me.  It needs to work with old Maple examples and it needs to cover the new uses.


Ray

victor_pv

#2026
Mar 25, 2015, 01:39 pm Last Edit: Mar 25, 2015, 01:59 pm by victor_pv
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.

oric_dan

#2027
Mar 25, 2015, 05:56 pm Last Edit: Mar 25, 2015, 06:24 pm by oric_dan
Quote
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
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.
https://github.com/PaulStoffregen/SPI

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.
Code: [Select]
// 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.

madias

#2028
Mar 25, 2015, 10:03 pm Last Edit: Mar 25, 2015, 10:06 pm by madias
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);


oric_dan

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.

2. 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.

Code: [Select]

      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!

rogerClark

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.

Freelance developer and IT consultant
www.rogerclark.net

rogerClark

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
Freelance developer and IT consultant
www.rogerclark.net

oric_dan

#2032
Mar 26, 2015, 01:34 am Last Edit: Mar 26, 2015, 01:35 am by oric_dan
Quote
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.









rogerClark

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

Freelance developer and IT consultant
www.rogerclark.net

oric_dan

#2034
Mar 26, 2015, 02:23 am Last Edit: Mar 26, 2015, 02:31 am by oric_dan
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.
http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090
http://www.digikey.com/product-search/en?&mpart=STM32F429I-DISCO

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

victor_pv

#2035
Mar 26, 2015, 02:45 am Last Edit: Mar 26, 2015, 02:52 am by victor_pv
@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.

rogerClark

#2036
Mar 26, 2015, 03:29 am Last Edit: Mar 26, 2015, 03:38 am by rogerClark
Dan Victor

Quote
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

Quote
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)
Freelance developer and IT consultant
www.rogerclark.net

rogerClark

@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 ;-(
Freelance developer and IT consultant
www.rogerclark.net

madias

@Dan: Also worth a look into: (Didn't here about it till I got a advertisment from ST last week)
http://www.openstm32.org/HomePage
should be available for linux and OSX Q2/15

oric_dan

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.

Go Up