cancel
Showing results for 
Search instead for 
Did you mean: 

Using mmap in C-Code from Linux application to access GPIOs. I want to control the GPIO PF4 on the STM32MP1 with mmap() due to speed requirements, but the pin is not toggling.

Led
Senior

Details:

HW: Phytec Sargas Board, which is similar to the STM32MP1-DK2.

Build environment: Cross compiling with SDK generated by Yocto.

Linux: Yocto build, based on st-image weston.

Device Tree configuration: As far as I understood not needed to access single GPIOs.

Any help is appreciated 🙂

Code (only partially):

#define MEM_DEV                 "/dev/mem"
#define GPIOF_START_ADDR        0x50007000
#define GPIOF_END_ADDR          0x500073FF
#define GPIOF_MAP_SIZE          (GPIOF_END_ADDR - GPIOF_START_ADDR)
 
#define GPIO_REG_MODER 0x00     /**< GPIO port mode register */
#define GPIO_REG_OTYPER 0x04    /**< GPIO port output type register */
#define GPIO_REG_BSRR 0x18      /**< GPIO port bit set/reset register */
 
#define GPIO_PIN_4                    ((uint16_t)0x0010U)
#define GPIO_PIN_OUTPUT_DIRECTION     0x01 /**< Output */
#define GPIO_PIN_OUTPUT_PUSHPULL      0x00 /**< Output Push Pull Mode */
 
int main(int argc, char **argv)
{
  int ret = EXIT_SUCCESS;
  static void *mmapBase = NULL; /* Virtual base address */
  signal(SIGINT, intHandler); /* Catch CTRL + C signal*/
  signal(SIGTERM, intHandler); /* Catch kill signal */
 
  /* Try to open the mem device special file */
  int fdMem = open(MEM_DEV, O_RDWR | O_SYNC);
  if (fdMem < 1)
  {
    exit(1);
  }
  
  /* Map memory region for the gpio registers */
  mmapBase = mmap(NULL,
          GPIOF_MAP_SIZE,
          PROT_READ | PROT_WRITE,
          MAP_SHARED,
          fdMem,
          GPIOF_START_ADDR);
  if (mmapBase == (void*) -1)
  {
    exit(1);
  }
 
  { /* MODER */
    /* Load the different gpio register pointers with its address */
    volatile uint32_t *gpioRegAddr = mmapBase + GPIO_REG_MODER;
    /* Get the value of the gpio direction register */
    uint32_t gpioRegVal = *gpioRegAddr;
    /* Clear the GPIO, write it back to the direction register */    
    gpioRegVal &= ~(0x03 << (4 * 2)); /* mask out the 2 bits giving the direction */
    gpioRegVal |= ((GPIO_PIN_OUTPUT_DIRECTION) << (4 * 2));
    *gpioRegAddr = gpioRegVal;
  }
 
  { /* OTYPE */
    /* Load the different gpio register pointers with its address */
    volatile uint32_t *gpioRegAddr = mmapBase + GPIO_REG_OTYPER;
    /* Get the value of the gpio direction register */
    uint32_t gpioRegVal = *gpioRegAddr;
    /* Clear the GPIO, write it back to the direction register */    
    gpioRegVal &= ~(0x0 << (4)); /* mask out */
    gpioRegVal |= ((GPIO_PIN_OUTPUT_PUSHPULL) << (4));
    *gpioRegAddr = gpioRegVal;
  }
      
  volatile uint32_t *const gpioSetClearDataOutAddr = mmapBase + GPIO_REG_BSRR;
  keepRunning = 1;
  while(keepRunning)
  {
    *gpioSetClearDataOutAddr = GPIO_PIN_4_REG_DEFINITION; /* set the pin */
    sleep_ms(500);
    *gpioSetClearDataOutAddr = (uint32_t)(GPIO_PIN_4_REG_DEFINITION << 16); /* reset the pin */
    sleep_ms(500);
  }
  return ret;
}

11 REPLIES 11
AntonioST
ST Employee

Hi @FTrie.1​ ,

I have checked the DT for OSD32MP1-BRK at line 100 and 107. I'm not sure this is what you are using now.

The two LED connected to the board are reported as GPIO_ACTIVE_LOW. This means that the LED gets turned ON when the GPIO is at LOW level.

In your code you should write 0x03000000 in BSRR to set LOW the GPIO PI8 and PI9 and turn ON the LEDs.

But you also mention that you read ODR and it is zero! It should have bits 8 and 9 set, accordingly to your write in BSRR.

Looks like the peripheral is kept in reset state.

Can you print, between line 41 and 47, the value of register RCC_AHB4RSTCLRR at address (mmapBase + 0x9AC)?

FTrie.1
Associate II

Hi @AntonioST​ ,

thanks a lot for the quick and helpful answer!

I figured out what my problem was. Apparently it was a casting problem.

initially i used:

volatile uint32_t *const gpioModerAddr = (uint32_t*)mmapBase + 0x00;

but i had to use:

volatile uint32_t * gpioModerAddr = (volatile uint32_t*)(mmapBase + 0x00);

I also can control the DCMI registers as this is my intended application.

Apperently without adding it to any device tree.