0

I am trying to access physical addresses registers on my ARM (https://4donline.ihs.com/images/VipMasterIC/IC/ATML/ATML-S-A0001248554/ATML-S-A0001248554-1.pdf) with mmap but I don't know what length to put.
For example, if I have a register at address 0xFFFFFCE8 in which I have access to 32 bit.
What should I put in mmap size_t ?

Thank you for you help !

EDIT :
Here and here we can see they put 4096, and on the first one it is a SAM9 almost the same as mine.
So, why did they put 4096 ?
Maybe because if I do :

#include <unistd.h>
long sz = sysconf(_SC_PAGESIZE);
printf("%ld",sz);

Th answer is 4096...

EDIT 2 :
Based on this post I could write this :

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>

#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define PIOD_START_ADDR                     0xFFFFFA00
#define PIOD_STOP_ADDR                      0xFFFFFC00
#define PIOD_SIZE                           (PIOD_STOP_ADDR-PIOD_START_ADDR)

#define PIO_WPMR_OFFSET                     0xE4    // PIO Write Protection Mode Register Bank D

#define PIO_PUER_OFFSET                     0x64    // PIO Pull-Up Enable Register Bank D
#define PIO_PUSR_OFFSET                     0x68    // PIO Pull-Up Status Register Bank D

#define LED7_ON                             0xFFDFFFFF  // LED7 Mask ON
#define LED7_OFF                            0xFFFFFFFF  // LED7 Mask OFF
#define DESABLE_WRITE_PROTECTION_BANK_D     0x50494F00  // Desable write protection

int main(void) {
    volatile void *gpio_D_addr;
    volatile unsigned int *gpio_pullup_enable_addr;
    volatile unsigned int *gpio_pullup_status_addr;
    volatile unsigned int *gpio_enable_write_addr;

    int fd = open("/dev/mem", O_RDWR|O_SYNC);
    if (fd < 0){
        fprintf(stderr, "Unable to open port\n\r");
        exit(fd);
    }

    gpio_D_addr = mmap(0, PIOD_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOD_START_ADDR);
    gpio_addr =  mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR);

    if(gpio_D_addr == MAP_FAILED){
        handle_error("mmap");
    }

    gpio_enable_write_addr = gpio_D_addr + PIO_WPMR_OFFSET;
    gpio_pullup_enable_addr = gpio_D_addr + PIO_PUER_OFFSET;
    gpio_pullup_status_addr = gpio_D_addr + PIO_PUSR_OFFSET;

    *gpio_enable_write_addr = DESABLE_WRITE_PROTECTION_BANK_D;

    *gpio_pullup_enable_addr = *gpio_pullup_status_addr & LED7_ON;

    return 0;
}

But I have a mmap: Invalid argument error. --> But by changing the mmap like so (thank to this thread): mmap(NULL, MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, PIOD_START_ADDR & ~MAP_MASK); with :

#define MAP_SIZE                            4096UL
#define MAP_MASK                            (MAP_SIZE - 1)

I no longer have the error but nothing happened...

Any idea ?

Tagadac
  • 383
  • 1
  • 3
  • 18

2 Answers2

1

Read Chapter 5 of the datasheet you provided as a link. It describes the various memories and memory mapping for this device. The address you gave is 32-bit, but you need to make sure about its mapping. That's where the chart on p. 18 comes in -- along with becoming familiar with the entire 1200-page datasheet if you really want to program these SAM devices at a low level.

The address you gave also seems to be for the PMC (power management controller) memory space (according to the map), so I'd review that section, chapter 21.

TomServo
  • 6,759
  • 5
  • 27
  • 41
  • Thank you for your help. I already saw this chapter, but see EDIT of my post above. – Tagadac Jun 02 '17 at 12:34
  • 1
    I have no idea about the 4096 value.. would take more research to understand that. But now, work calls :( – TomServo Jun 02 '17 at 13:29
  • 1
    By doing this `#include long sz = sysconf(_SC_PAGESIZE); printf("%ld",sz);` we have `4096`. So the size of the page is 4096. – Tagadac Jun 02 '17 at 14:16
1

Thank you to @vlk and his library in python I could make it work ! Here is a little example for toggling a LED :

#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <fcntl.h>


#define handle_error(msg) \
           do { perror(msg); exit(EXIT_FAILURE); } while (0)

#define _PIOD_BANK_D                            0xA00

#define _PIO_OFFSET                             0xFFFFF000

/* When executing this on the board :
    long sz = sysconf(_SC_PAGESIZE);
    printf("%ld\n\r",sz);
   We have 4096.
*/
#define _MAP_SIZE                           0x1000  // 4096 

#define _WPMR_OFFSET                        0x0E4   // PIO Write Protection Mode Register Bank D

#define _PIO_ENABLE                         0x000
#define _PIO_DISABLE                        0x004
#define _PIO_STATUS                         0x008
#define _OUTPUT_ENABLE                      0x010
#define _OUTPUT_DISABLE                     0x014
#define _OUTPUT_STATUS                      0x018
#define _FILTER_ENABLE                      0x020
#define _FILTER_DISABLE                     0x024
#define _FILTER_STATUS                      0x028
#define _OUTPUT_DATA_SET                    0x030
#define _OUTPUT_DATA_CLEAR                  0x034
#define _OUTPUT_DATA_STATUS                 0x038
#define _PIN_DATA_STATUS                    0x03c
#define _MULTI_DRIVER_ENABLE                0x050
#define _MULTI_DRIVER_DISABLE               0x054
#define _MULTI_DRIVER_STATUS                0x058
#define _PULL_UP_DISABLE                    0x060
#define _PULL_UP_ENABLE                     0x064
#define _PULL_UP_STATUS                     0x068
#define _PULL_DOWN_DISABLE                  0x090
#define _PULL_DOWN_ENABLE                   0x094
#define _PULL_DOWN_STATUS                   0x098

#define _DISABLE_WRITE_PROTECTION           0x50494F00  // Desable write protection

#define LED_PIN                                 21

int main(void) {

    volatile void *gpio_addr;
    volatile unsigned int *gpio_enable_addr;
    volatile unsigned int *gpio_output_mode_addr;
    volatile unsigned int *gpio_output_set_addr;
    volatile unsigned int *gpio_output_clear_addr;
    volatile unsigned int *gpio_data_status_addr;
    volatile unsigned int *gpio_write_protection_addr;

    int fd = open("/dev/mem", O_RDWR|O_SYNC);
    if (fd < 0){
        fprintf(stderr, "Unable to open port\n\r");
        exit(fd);
    }


    gpio_addr = mmap(NULL, _MAP_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PIO_OFFSET);


    if(gpio_addr == MAP_FAILED){
        handle_error("mmap");
    }


    gpio_write_protection_addr = gpio_addr + _PIOD_BANK_D + _WPMR_OFFSET;

    gpio_enable_addr = gpio_addr + _PIOD_BANK_D + _PIO_ENABLE;

    gpio_output_mode_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_ENABLE;

    gpio_output_set_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_SET;

    gpio_output_clear_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_CLEAR;

    gpio_data_status_addr = gpio_addr + _PIOD_BANK_D + _OUTPUT_DATA_STATUS;


    *gpio_write_protection_addr = _DISABLE_WRITE_PROTECTION;

    *gpio_enable_addr = 1 << LED_PIN;
    *gpio_output_mode_addr = 1 << LED_PIN; // Output


    // If LED
    if((*gpio_data_status_addr & (1<<LED_PIN)) > 0){
        *gpio_output_clear_addr = 1 << LED_PIN;
    }else{
        *gpio_output_set_addr = 1 << LED_PIN;
    }

    return 0;
}

I had to put _PIO_OFFSET to 0xFFFFF000, and add to the address the value of the D Bank (0xA00), instead of 0xFFFFFA00 because it resulted with mmap: Invalid argument. Don't know why..

EDIT :
Found the solution with the mmap example :

#define _PIO_OFFSET                         0xFFFFFA00 // Instead of 0xFFFFF000
#define _MAP_SIZE                           0x1000  // 4096 
#define _MAP_MASK                           (_MAP_SIZE - 1)
#define _PA_OFFSET                          _PIO_OFFSET & ~_MAP_MASK

And the mmap :

gpio_addr = mmap(NULL, _MAP_SIZE + _PIO_OFFSET - _PA_OFFSET, PROT_READ | PROT_WRITE, MAP_SHARED, fd, _PA_OFFSET);

And for the assignation :

gpio_enable_addr = gpio_addr + _PIO_OFFSET - (_PA_OFFSET) + _PIO_ENABLE;
Tagadac
  • 383
  • 1
  • 3
  • 18