3

I'm writing a simple program to set and clear a pin (the purpose is to use that pin as a custom spi_CS). I'm able to export that pin (gpio1_17, port 9 pin 23 bb white) and to use that trough the filesystem but I have to drive it faster.

This is the code:

uint32_t *gpio;

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

gpio =(uint32_t *) mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, MAP_SHARED, fd, GPIO1_offset); // start of GPIOA

if(gpio == (void *) -1) {
    printf("Memory map failed.\n");
    exit(0);
} else {
    printf("Memory mapped at address %p.\n", gpio);
}

printf("\nGPIO_OE:%X\n",gpio[GPIO_OE/4]);
gpio[GPIO_OE/4]=USR1;
printf("\nGPIO_OE:%X\n",gpio[GPIO_OE/4]);

printf("\nGPIO_CLEARDATAOUT:%X\n",gpio[GPIO_CLEARDATAOUT/4]);
gpio[GPIO_CLEARDATAOUT/4]=USR1;
printf("\nGPIO_CLEARDATAOUT:%X\n",gpio[GPIO_CLEARDATAOUT/4]);


sleep(1);

printf("\nGPIO_SETDATAOUT%X\n",gpio[GPIO_SETDATAOUT/4]);
gpio[GPIO_DATAOUT/4]=USR1;
printf("\nGPIO_SETDATAOUT%X\n",gpio[GPIO_SETDATAOUT/4]);

with

#define GPIO1_offset  0x4804c000
#define GPIO1_size  0x4804cfff-GPIO1_offset
#define GPIO_OE  0x134
#define GPIO_SETDATAOUT  0x194
#define GPIO_CLEARDATAOUT  0x190
#define GPIO_DATAOUT 0x13C
#define USR1  1<<17

I'm able to outputenable that pin, beacuse if I put it high before running the program, that ping goes low. But I cannot set and reset it. Any ideas?

JosephITA
  • 502
  • 2
  • 11
  • 21
  • 1
    For anyone reading this after @RexLogan's comment, in more recent kernel versions, the /4 is required. See this answer: https://stackoverflow.com/a/20874882/2712525 The magic numbers here just so happen to be the OP's values divided by 4. – Will Eccles Jan 20 '21 at 17:53

1 Answers1

-1

Why are you directly modifying the registers? It is way easier to just use it as a linux GPIO:

#define GPIO_1_17                  "49"                        

int gpio;
status_codes stat = STATUS_SUCCESS;

//Export our GPIOs for use
if((gpio = open("/sys/class/gpio/export", O_WRONLY)) >= 0) {
    write(gpio, GPIO_1_17, strlen(GPIO_1_17));
    close(gpio);
} else {
    stat = STATUS_GPIO_ACCESS_FAILURE;
    break;
}

//Set the direction and pull low
if((gpio = open("/sys/class/gpio/gpio" GPIO_1_17 "/direction", O_WRONLY)) >= 0) {
    write(gpio, "out", 3);  // Set out direction
    close(gpio);
} else {
    stat = STATUS_GPIO_ACCESS_FAILURE;
    break;
}
if((gpio = open("/sys/class/gpio/gpio" GPIO_1_17 "/value", O_WRONLY)) >= 0) {
    write(gpio, "0", 1);    // Pull low
    close(gpio);
} else {
    stat = STATUS_GPIO_ACCESS_FAILURE;
    break;
}

Then just make sure it is muxed as a gpio in your inits.

As far as the mmap method you have above you addressing looks correct. The addresses in the ref manual are byte addresses and you are using a 32-bit pointer so what you have there is correct. However, this line: gpio[GPIO_OE/4]=USR1 makes every pin on GPIO1 an output except for 17 which it makes an input (0 = output and 1 = input). You probably meant this: gpio[GPIO_OE/4] &= ~USR1

Also i believe you meant to have gpio[GPIO_SETDATAOUT/4]=USR1; instead of gpio[GPIO_DATAOUT/4]=USR1; They will both cause GPIO1_17 to be set; however, using what you have will also set all the other pins on GPIO1 to be 0.

I would definitely recommend using the designed kernel interfaces because mmap'ing stuff that is also controlled by the kernel can be asking for trouble.

Good Luck! : )

EDIT: My bad just realized you said why you were not driving it directly through the file system because you needed to drive it faster! You may also want to consider writing/modifying the SPI driver so that the stuff is being done in Kernel land if speed is what your after. The omap gpio interfaces are simple to use there as well, just request and set : ).

jcc273
  • 119
  • 6
  • Yes! Accessing them trough their register increase a lot their speed! I must say that am335x is not the right processer for that kind of applications (fast gpio branching). Thanks! – JosephITA Jun 10 '15 at 13:06