Author Topic: STM32F767 (and simmilar) raw GPIO use  (Read 6767 times)

0 Members and 1 Guest are viewing this topic.

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
STM32F767 (and simmilar) raw GPIO use
« on: January 04, 2017, 07:32:04 pm »
Hi

I've asked this same thing on the mbed question forum, but I got no solution in two days already.
For a project I'm doing I got the Nucleo144 board which has a STM32F767 mcu.
I need to have fast access to the GPIO so I'm trying to handle them directly via registers.
I've found more than one tutorial on using GPIO via registers for STM but none of them work on the mbed online editor.
I just can't find an example or documentation that explains how to get that working for the mcu I have.
I just get that the register name is a syntax error, so either its different, or I am missing some library specific for that mcu.
 

Offline FreddyVictor

  • Regular Contributor
  • *
  • Posts: 164
  • Country: gb
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #1 on: January 04, 2017, 10:48:00 pm »
Just a suggestion (as I usually use SPL or HAL) & havn't used mbed !

Have you included the correct controller-specific include file ?
eg: stm32f767xx.h - this should be included in your project (should already be included with mbed I would have thought ??)

then download the reference manual RM0410.pdf - see chapter 6 for GPIO register names
 

Offline DaJMasta

  • Super Contributor
  • ***
  • Posts: 2298
  • Country: us
    • medpants.com
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #2 on: January 05, 2017, 06:28:57 am »
Also haven't used mbed, but using the HAL libraries and the Cube configuration software, it will autogenerate the GPIO pin configurations when building the template initially, and that automatic initialization code in your main program may be able to point you to the registers that are being used and a way to set them.

The actual functions used do vary based on the library versions, and they actually vary somewhat between processor series (F1XX will be different from F7XX and L1XX, for example).

Often for the basic stuff, just taking a look at any sample programs they supply can help - if you can find your classic hello-world pin blinker program that will compile for your chip, it probably shows you the register and functions you need for that pin in the code.
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #3 on: January 05, 2017, 03:09:50 pm »
Quote
Have you included the correct controller-specific include file ?
Not sure, I don't even know which one is it, or where to find it.
Including  stm32f767xx.h or  stm32f7xx.h does nothing.

Quote
Also haven't used mbed, but using the HAL libraries and the Cube configuration software, it will autogenerate the GPIO pin configurations when building the template initially, and that automatic initialization code in your main program may be able to point you to the registers that are being used and a way to set them.
I have installed cube, but I have no idea how to get those configuration then in the embed online editor.

I've saw people using eclipse, but I have yet to figure out how to set it all up.

I have mostly been using PIC with MPLABX, where things are much simpler, so I don't even know what I need to look for here.

Quote
Often for the basic stuff, just taking a look at any sample programs they supply can help - if you can find your classic hello-world pin blinker program that will compile for your chip, it probably shows you the register and functions you need for that pin in the code.
Hello world programs work, but they all use the arduino style functions, in fact all of the code I found uses them, nobody seems to bother with raw port access.
There is some library on mbed that is supposed to simulate a parallel bus interface via GPIO but it won't compile since it says mentioned registers are unknown.
 

Offline gperoni

  • Contributor
  • Posts: 38
  • Country: it
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #4 on: January 05, 2017, 08:35:52 pm »
You can download SystemWorkbench, it's a very nice tool to develop for this platform. Once you do that just port the GPIO examples from the cube. You will be fine.
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #5 on: January 06, 2017, 05:09:31 am »
You can download SystemWorkbench, it's a very nice tool to develop for this platform. Once you do that just port the GPIO examples from the cube. You will be fine.
I'll give it a try.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #6 on: January 06, 2017, 11:17:15 am »
Quote
I need to have fast access to the GPIO so I'm trying to handle them directly via registers.
I've found more than one tutorial on using GPIO via registers for STM but none of them work on the mbed online editor.
I just get that the register name is a syntax error, so either its different, or I am missing some library specific for that mcu.
Perhaps you should show us an example of the code you are trying to use, and the actual error messages that are generated.  You might be trying to use a syntax that someone will recognize as being "obviously wrong."
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #7 on: January 07, 2017, 04:21:25 am »
You can download SystemWorkbench, it's a very nice tool to develop for this platform. Once you do that just port the GPIO examples from the cube. You will be fine.
I installed it, but there is no STM32F767 when choosing the used part.
I downloaded the STM32CubeF7 package, but that is just a bunch of files, among which there seems to be a ton of examples, including GPIO, but I have no idea how to load them.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #8 on: January 07, 2017, 09:10:24 am »
PS.  I tried my first mbed program!  I didn't have any troubles modifying the basic BLINK example to do raw GPIO, as follows:
Code: [Select]
int main() {
    while(1) {
        GPIOA->ODR = 0;  // added line
Compiled for the Nucleo 767 board.  No other #includes or anything were needed.
 

Offline gperoni

  • Contributor
  • Posts: 38
  • Country: it
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #9 on: January 07, 2017, 09:24:33 am »
Have you tried updating the eclipse plugins? What's the difference between STM32F767 and for example 46? I think you just might need to edit some definitions like ram, memory space (it's not as hard as it seems and some of the other F7 options should work).
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #10 on: January 07, 2017, 05:35:09 pm »
PS.  I tried my first mbed program!  I didn't have any troubles modifying the basic BLINK example to do raw GPIO, as follows:
Code: [Select]
int main() {
    while(1) {
        GPIOA->ODR = 0;  // added line
Compiled for the Nucleo 767 board.  No other #includes or anything were needed.

Yes, that works, in fact I have this code:

Code: [Select]
int main() {
    unsigned int i=0;
    GPIOD->ODR = 0xFFFFFFFF; //Opposite of pic???
    //RCC->AHBENR |= RCC_AHBENR_GPIOCEN; - this does not compile
    while (1)
    {
        GPIOD->BSRR = i++;
    }
}

It compiles, it loads, but nothing happens.
I think I am missing the clock configurations, which should be set by the RCC which is not recognized.


Quote
Have you tried updating the eclipse plugins? What's the difference between STM32F767 and for example 46? I think you just might need to edit some definitions like ram, memory space (it's not as hard as it seems and some of the other F7 options should work).
I don't know. I am still fairly new to arm and definitely new to STM, so I still don't know how everything works here I only have experience with pic, 8051 and some atmega when it comes to microcontrollers.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #11 on: January 07, 2017, 10:50:33 pm »
Quote
//RCC->AHBENR |= RCC_AHBENR_GPIOCEN; - this does not compile
Ah hah!  Now we are getting somewhere.  The F767, being a BIG FINE CHIP, has multiple buses (?  Multiple AHB control registers, anyway), so anything on ONE of the AHBs is going to have a number associated with it.
For GPIOC, I believe you want:
Code: [Select]
        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
That nicely explains why the existing examples weren't helpful - they all run on chips with simpler bus structures.
I didn't really find a "friendly" table of which peripherhals are in which AHB registers, see Table 23 (page 214) in the RM0410 Reference manual.  Most of the normal peripherals in in AHB1*; the STM32f767xx.h file is readable, once you figure out that you want to search for "ENR_xxxx" (but of course it's a bit difficult to GET, being distributed mainly as a part of STMCUBE...):

Code: [Select]
/********************  Bit definition for RCC_AHB1ENR register  ***************/
#define  RCC_AHB1ENR_GPIOAEN                 0x00000001U
#define  RCC_AHB1ENR_GPIOBEN                 0x00000002U
#define  RCC_AHB1ENR_GPIOCEN                 0x00000004U
#define  RCC_AHB1ENR_GPIODEN                 0x00000008U
#define  RCC_AHB1ENR_GPIOEEN                 0x00000010U
#define  RCC_AHB1ENR_GPIOFEN                 0x00000020U
#define  RCC_AHB1ENR_GPIOGEN                 0x00000040U
#define  RCC_AHB1ENR_GPIOHEN                 0x00000080U
#define  RCC_AHB1ENR_GPIOIEN                 0x00000100U
#define  RCC_AHB1ENR_GPIOJEN                 0x00000200U
#define  RCC_AHB1ENR_GPIOKEN                 0x00000400U
#define  RCC_AHB1ENR_CRCEN                   0x00001000U
#define  RCC_AHB1ENR_BKPSRAMEN               0x00040000U
#define  RCC_AHB1ENR_DTCMRAMEN               0x00100000U
#define  RCC_AHB1ENR_DMA1EN                  0x00200000U
#define  RCC_AHB1ENR_DMA2EN                  0x00400000U
#define  RCC_AHB1ENR_DMA2DEN                 0x00800000U
#define  RCC_AHB1ENR_ETHMACEN                0x02000000U
#define  RCC_AHB1ENR_ETHMACTXEN              0x04000000U
#define  RCC_AHB1ENR_ETHMACRXEN              0x08000000U
#define  RCC_AHB1ENR_ETHMACPTPEN             0x10000000U
#define  RCC_AHB1ENR_OTGHSEN                 0x20000000U
#define  RCC_AHB1ENR_OTGHSULPIEN             0x40000000U

/********************  Bit definition for RCC_AHB2ENR register  ***************/
#define  RCC_AHB2ENR_DCMIEN                  0x00000001U
#define  RCC_AHB2ENR_JPEGEN                  0x00000002U
#define  RCC_AHB2ENR_RNGEN                   0x00000040U
#define  RCC_AHB2ENR_OTGFSEN                 0x00000080U

/********************  Bit definition for RCC_AHB3ENR register  ***************/
#define  RCC_AHB3ENR_FMCEN                  0x00000001U
#define  RCC_AHB3ENR_QSPIEN                 0x00000002U

   
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #12 on: January 08, 2017, 12:16:31 am »

Ah hah!  Now we are getting somewhere.  The F767, being a BIG FINE CHIP, has multiple buses (?  Multiple AHB control registers, anyway), so anything on ONE of the AHBs is going to have a number associated with it.
For GPIOC, I believe you want:
Code: [Select]
        RCC->AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
Yes, that works now! Thanks!

The code I posted previously is not really correct, BSRR register is not what I was supposed to be using, and port direction is set with MODE register.

Code:
Code: [Select]
int main() {
    unsigned int i=0,j=0;
   

    RCC->AHB1ENR |= RCC_AHB1ENR_GPIODEN;
   
    GPIOD-> MODER |= (GPIO_MODER_MODER0_0|GPIO_MODER_MODER1_0) ;
    GPIOC->OTYPER &= ~(GPIO_OTYPER_OT_0 | GPIO_OTYPER_OT_1) ;
    // Ensure push pull mode selected--default

    GPIOC->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0|GPIO_OSPEEDER_OSPEEDR1);
    //Ensure maximum speed setting (even though it is unnecessary)

    //GPIOD->ODR = 0xFFFFFFFF; 
    while (1)
    {
        GPIOD->ODR  = i++;
        for(j=0;j<3;j++);
       
    }
}

There is a speed limit on the GPIO, toggling it at full speeds latches the pin for some time giving out some low frequency with lots of jitter.
When I slowed down the loop it started working properly again, the code above is the fastest it can toggle, and my analog oscilloscope shows it to be about 50MHz.  :D
« Last Edit: January 08, 2017, 12:19:39 am by Dajgoro »
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 2365
  • Country: de
    • Frank Buss
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #13 on: January 08, 2017, 12:53:25 am »
With this code:

Code: [Select]
while (1) {
GPIOD->ODR ^= GPIO_PIN_12;
}

I get 12 MHz, with my STMF4 discovery board, running at 168 MHz. Taking a look at the assembly code for it (Keil uVision), it looks like this:

Code: [Select]
|L8.246|
        LDR      r1,[r0,#0]
        EOR      r1,r1,#0x1000
        STR      r1,[r0,#0]
        B        |L8.246|

So it should run much faster, but the APB1 peripherals can only be clocked with 42 MHz max, so I guess it adds some wait states when accessing it, and might need even longer because of reading and writing to it.

Another trick for fast accessing individual GPIO pins, without loading first the value of the other 31 pins for the usual load/modify/write cycle, is using the bit-banding feature:

http://mightydevices.com/?p=144

Note, this works even for the internal SRAM, which is pretty cool. I couldn't find the bitband macro for CubeMX, but it is easy to calculate the address yourself. This code here uses bitbanding for the pin toggling:

Code: [Select]
    volatile void* address = &GPIOD->ODR;
    uint32_t bit = 12;
    uint32_t bb_base = 0x42000000;
    uint32_t bb_ref = 0x40000000;
    volatile uint32_t* pin = (volatile uint32_t*)(bb_base + ((uint32_t)address - bb_ref) * 32 + bit * 4);
    while (1) {
        *pin = 1;
        *pin = 0;
    }

It toggles the pin with 21.2 MHz, which is the fastest you can do for GPIO (the GPIO clock is 42 MHz). The assembly code looks like this (only showing the loop) :

|L8.244|
        STR      r2,[r0,#0]
        STR      r1,[r0,#0]
        B        |L8.244|

Of course, you could do this with the BSRR register as well, but bitbanding is very useful in general. You shouldn't write an integer counter to ODR without loading the old value first, and masking the bits you want to change, unless you are sure that it doesn't harm any of the other hardware that are connected to your pins.

BTW: If you need to output lots of data fast, and without gaps in the stream, and still want to do something in parallel with your CPU, you could try to use the SRAM controller with DMA transfer (if your STM32 chip has an SRAM model). Worked pretty well when I tried it, using two DIY 4 bit R2R DACs, despite the fact that the datasheet says that the circular mode (needed for gap-less transfers, to prepare the second buffer while the first buffer is transferred and vice-versa) is not allowed for memory to memory transfers:

https://plus.google.com/+FrankBussProgrammer/posts/jQidPgbtKoW
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #14 on: January 08, 2017, 04:15:48 am »
What I actually need to do is transfer data to a bunch of pic18f which are connected to the stm with the parallel slave port. Having an external bus access would be even better, and I though about it, but did not bother so far looking into it.
 

Offline westfw

  • Super Contributor
  • ***
  • Posts: 4199
  • Country: us
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #15 on: January 08, 2017, 04:39:21 am »
Quote
There is a speed limit on the GPIO, toggling it at full speeds latches the pin for some time giving out some low frequency with lots of jitter.
When I slowed down the loop it started working properly again, the code above is the fastest it can toggle, and my analog oscilloscope shows it to be about 50MHz.
That seems unlikely, given that the datasheet says "[size=0pt]Fast toggle capable of changing every two clock cycle", and it would result in a lot of complaints...  Are you sure it's not your scope that's giving out?

The way I read the datasheets and .h files, the GPIO registers are directly on the AHB bus, and don't have to go through an additional APB bridge.

[/size]
Code: [Select]
    GPIOC->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0|GPIO_OSPEEDER_OSPEEDR1);OSPEEDR has fields for each bit.   I don't know what will happen if you output to the whole ODR when different bits are set to different speeds.
Use 0xFFFFFFFF for full speed on all bits
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 2365
  • Country: de
    • Frank Buss
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #16 on: January 08, 2017, 02:14:31 pm »
The way I read the datasheets and .h files, the GPIO registers are directly on the AHB bus, and don't have to go through an additional APB bridge.

Right, it is on the AHB bus, so why does my code result in 21 MHz? This was my code:

Code: [Select]
|L8.244|
        STR      r2,[r0,#0]
        STR      r1,[r0,#0]
        B        |L8.244|

I even unrolled the loop 8 times (16 STR instructions), but no changes. Looks like the STR instruction needs always 1 cycle on a Cortex M4:

http://infocenter.arm.com/help/topic/com.arm.doc.ddi0439b/CHDIJAFG.html

I have the instruction cache enabled, to avoid the flash wait states. With 168 MHz CPU clock and the same AHB clock (I verified it in the CubeMX clock configuration, HCLK to AHB clock output is 168 MHz) the unrolled version should create bursts of 84 MHz, interrupted by the time for the branch instruction, or at least 42 MHz, if it is only possible to toggle it every two clocks.

Quote
[/font][/size]
Code: [Select]
    GPIOC->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0|GPIO_OSPEEDER_OSPEEDR1);OSPEEDR has fields for each bit.   I don't know what will happen if you output to the whole ODR when different bits are set to different speeds.
Use 0xFFFFFFFF for full speed on all bits

The speed is only for the slew rate, it doesn't change the rate how fast you can toggle the pins.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline FrankBuss

  • Supporter
  • ****
  • Posts: 2365
  • Country: de
    • Frank Buss
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #17 on: January 08, 2017, 02:19:22 pm »
What I actually need to do is transfer data to a bunch of pic18f which are connected to the stm with the parallel slave port. Having an external bus access would be even better, and I though about it, but did not bother so far looking into it.

The application note AN4666 looks interesting for this. Nice trick to configure the timer for PWM and use it to trigger the DMA to transfer the data, and using the PWM output in addition for a clock line.
So Long, and Thanks for All the Fish
Electronics, hiking, retro-computing, electronic music etc.: https://www.youtube.com/c/FrankBussProgrammer
 

Offline DajgoroTopic starter

  • Frequent Contributor
  • **
  • Posts: 322
  • Country: hr
    • hackaday.io
Re: STM32F767 (and simmilar) raw GPIO use
« Reply #18 on: January 08, 2017, 08:29:00 pm »
Quote
There is a speed limit on the GPIO, toggling it at full speeds latches the pin for some time giving out some low frequency with lots of jitter.
When I slowed down the loop it started working properly again, the code above is the fastest it can toggle, and my analog oscilloscope shows it to be about 50MHz.
That seems unlikely, given that the datasheet says "[size=0pt]Fast toggle capable of changing every two clock cycle", and it would result in a lot of complaints...  Are you sure it's not your scope that's giving out?

The way I read the datasheets and .h files, the GPIO registers are directly on the AHB bus, and don't have to go through an additional APB bridge.

[/size]
Code: [Select]
    GPIOC->OSPEEDR |= (GPIO_OSPEEDER_OSPEEDR0|GPIO_OSPEEDER_OSPEEDR1);OSPEEDR has fields for each bit.   I don't know what will happen if you output to the whole ODR when different bits are set to different speeds.
Use 0xFFFFFFFF for full speed on all bits
My scope is not from this era, but it still manages to pick up signals.
I took some photos showing what is going on:



A - Shows the fastest code I have running
B - Even that code generates some sort of glitch, its rare so it was a bit hard to catch on the oscilloscope
C - Shows the signal with no delay loop, and as you may see on the slew rate, its pretty slow. When I zoom in there is no other signal except noise.
« Last Edit: February 19, 2017, 02:03:42 am by Dajgoro »
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf