Handle GPIO in User Space ARM9 Embedded Linux AM1808 - embedded

I have to interface my GSM module with the AM1808 based on ARM9.
I have assigned all the GPIO pins to the Da850.c as well as mux.h files. I successfully created a uImage and inserted that image in my flash.
I need to handle some of that GPIO from User application.
I know that we can handle the GPIO from the Kerel space but i need to handle from the user space.
As for example I have assigned a GPIO for power key to GSM module. I need to change the pin means (HIGH or LOW) through application.
Ok i have written a following code to access it from the User Space,
#include <stdio.h>
#include <time.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <unistd.h>
#include "GSMpwr.h"
#define BS_GSM_PWR_REGISTER 0x01E26014
#define BS_DCDS_MASK 0x00000004
int fd; // Memory device descriptor
unsigned long *pPWR;
unsigned short GetGSMpwr(void)
{
#if defined __HOST_ARM
unsigned long dcd_value = *pPWR;
return (pwr_value >> 7) & 0x01;
#endif
}
void InitializeGSMpwr(void)
{
#if defined __HOST_ARM
int page_size = getpagesize();
unsigned int MAP_addr;
unsigned int reg_addr;
unsigned char *pTemp; // Pointer to GSMpwr register
/*
* Open memory and get pointer to GSMpwr register in the FPGA
*/
if((fd = open("/dev/mem", O_RDWR | O_SYNC)) < 0)
{
printf("failed to open /dev/mem");
return;
}
else
{
MAP_addr = (BS_GSM_PWR_REGISTER & ~(page_size - 1));
pTemp = (unsigned char *)mmap(NULL, page_size,(PROT_READ | PROT_WRITE),MAP_SHARED,fd,MAP_addr);
if((pTemp == MAP_FAILED) || (pTemp == NULL))
{
printf("failed to map /dev/mem");
return;
}
else
{
printf(“Memory Mapped at Address %p. \n”,pTemp);
}
virt_addr = map_base + (control & MAP_MASK);
reg_addr = (BS_GSM_PWR_REGISTER & (page_size - 1));
pPWR = (unsigned long*)(pTemp + reg_addr);
printf("GSM PWR PIN mapped in Application\n");
}
I can only read that pin through this code, Now i want to use that pin as an output and want to go high and low with the time interval of 3sec.

The easiest way is to utilize GPIO support in sysfs, where you could control all the exported GPIO's. Please have a look at the Linux kernel GPIO documentation, in particular, Sysfs Interface for Userspace part.
After you have enabled GPIO support in sysfs (GPIO_SYSFS), the GPIO control would be as easy as:
Example
GPIO=22
cd /sys/class/gpio
ls
echo $GPIO > /sys/class/gpio/export
ls
Notice on the first ls that gpio22 doesn't exist, but does after you export GPIO 22 to user space.
cd /sys/class/gpio/gpio$GPIO
ls
There are files to set the direction and retrieve the current value.
echo "in" > direction
cat value
You can configure the GPIO for output and set the value as well.
echo "out" > direction
echo 1 > value
Example is taken from here.

I got it please find following code for that,I got the Specific pin address and i have accessed that pin like,
unsigned short GetGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
return (pwr_value >> 1) & 0x01;
}
unsigned short SetGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
*pPWR = ~((pwr_value >> 1) & 0x01);
}
unsigned short ClrGSMpwr(void)
{
unsigned long pwr_value = *pPWR;
printf("GSM_PWR:check Start : %ld",pwr_value);
*pPWR = 256;
}`

Related

I2C communication between PIC32 and LCD

I am trying to communicate with LCD2041 using I2C . I am using PIC32MM curiosity board . I wrote the following code on MP lab code configurator , but the status for I2c communications is stuck on I2C2_MESSAGE_PENDING . I need help on what I might have done wrong or what I am missing .
#include <stdint.h>
#include <string.h>
#include <xc.h>
#include "mcc_generated_files/mcc.h"
//#include "lcd_i2c.h"
#define slave_Adress 0b01010000
void ByteDelay(void){
// Delay between bytes required by LCD2041 spec
DELAY_microseconds(625);
}
void ReadDelay(void){
// Delay between read commands required by LCD2041 spec
DELAY_milliseconds(3);
}
void TransactionDelay(void){
// Delay between transactions required by LCD2041 spec
DELAY_microseconds(375);
}
int main(void)
{
SYSTEM_Initialize();
uint8_t data = 0xFE; // host to tell data are output via I2c
uint8_t lcd_clear_display = 0xA4; // command to clear LCD
TRISBbits.TRISB2 = 1; // set B2 (scl) as input
TRISBbits.TRISB3 = 1; // set B3 (SDA) as input
I2C2_Initialize() ;
I2C2_MESSAGE_STATUS status ;
I2C2_MasterWrite(data, 1 , slave_Adress, &status);
ByteDelay();
if ( status == I2C2_MESSAGE_PENDING) {led_3_SetHigh();}
return 1;
}
The default slave address for the LCD is 0x50
I had a similar error once with an pic18f and mcc. I forgot to activate the global interrups. I don't see a place where you do that in your code.

Addressing pins of Register in microcontrollers

I'm working on Keil software and using LM3S316 microcontroller. Usually we address registers in microcontrollers in form of:
#define GPIO_PORTC_DATA_R (*((volatile uint32_t *)0x400063FC))
My question is how can I access to single pin of register for example, if I have this method:
char process_key(int a)
{ PC_0 = a ;}
How can I get PC_0 and how to define it?
Thank you
Given say:
#define PIN0 (1u<<0)
#define PIN1 (1u<<1)
#define PIN2 (1u<<2)
// etc...
Then:
char process_key(int a)
{
if( a != 0 )
{
// Set bit
GPIO_PORTC_DATA_R |= PIN0 ;
}
else
{
// Clear bit
GPIO_PORTC_DATA_R &= ~PIN0 ;
}
}
A generalisation of this idiomatic technique is presented at How do you set, clear, and toggle a single bit?
However the read-modify-write implied by |= / &= can be problematic if the register might be accessed in different thread/interrupt contexts, as well as adding a possibly undesirable overhead. Cortex-M3/4 parts have a feature known as bit-banding that allows individual bits to be addressed directly and atomically. Given:
volatile uint32_t* getBitBandAddress( volatile const void* address, int bit )
{
__IO uint32_t* bit_address = 0;
uint32_t addr = reinterpret_cast<uint32_t>(address);
// This bit maniplation makes the function valid for RAM
// and Peripheral bitband regions
uint32_t word_band_base = addr & 0xf0000000u;
uint32_t bit_band_base = word_band_base | 0x02000000u;
uint32_t offset = addr - word_band_base;
// Calculate bit band address
bit_address = reinterpret_cast<__IO uint32_t*>(bit_band_base + (offset * 32u) + (static_cast<uint32_t>(bit) * 4u));
return bit_address ;
}
Then you can have:
char process_key(int a)
{
static volatile uint32_t* PC0_BB_ADDR = getBitBandAddress( &GPIO_PORTC_DATA_R, 0 ) ;
*PC0_BB_ADDR = a ;
}
You could of course determine and hard-code the bit-band address; for example:
#define PC0 (*((volatile uint32_t *)0x420C7F88u))
Then:
char process_key(int a)
{
PC0 = a ;
}
Details of the bit-band address calculation can be found ARM Cortex-M Technical Reference Manual, and there is an on-line calculator here.

Delayed uart command execution

I'm writing a small embedded program, where I send some commands over uart to the atmega328p chip. The commands start with the character $ and end with the character # (so I know when to perform the parsing). Upon receiving the command I parse it and turn the device on (COMMAND:TURN_ON_I1) or off (COMMAND:TURN_OFF_I1). The application currently looks like this:
// ------- Defines -------- //
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/power.h>
#include <stdio.h>
#include <string.h>
#include "pinDefines.h"
#include "USART.h"
#define RECEIVE_BUFFER_SIZE 100
// Control output value
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
// Set pin mode (input or output)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
// The DDRD port contains only two pins:
#define REL_BTN_SIM_2 PD6 // PD6 = REL_BTN_SIM_2
void initUSART(void) { /* requires BAUD */
UBRR0H = UBRRH_VALUE; /* defined in setbaud.h */
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
/* Enable USART transmitter/receiver */
UCSR0B = (1 << TXEN0) | (1 << RXEN0);
UCSR0C = (1 << UCSZ01) | (1 << UCSZ00); /* 8 data bits, 1 stop bit */
}
void printString(const char myString[]) {
uint8_t i = 0;
while (myString[i]) {
transmitByte(myString[i]);
i++;
}
}
uint8_t receiveByte(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait for incoming data */
return UDR0; /* return register value */
}
void transmitByte(uint8_t data) {
/* Wait for empty transmit buffer */
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = data; /* send data */
}
int main(void) {
//$COMMAND:TURN_ON_I1#
//$COMMAND:TURN_OFF_I1#
char s[RECEIVE_BUFFER_SIZE];
char readSerialCharacter;
// -------- Inits --------- //
DDRB = 0b00000111;
DDRC = 0b00001000;
DDRD = 0b11000000;
initUSART();
// ------ Event loop ------ //
while (1) {
printString("Waiting for the start of string (char $).\r\n");
do { } while ( receiveByte() != '$'); // Wait for start of string.
// Fill the array until the end of transmission is received
int i=0;
do {
// If nearing end of buffer, don't fill the buffer and exit the loop
if(i<RECEIVE_BUFFER_SIZE-1){
readSerialCharacter = receiveByte();
s[i++] = readSerialCharacter;
}else
break;
} while (readSerialCharacter != '#'); // Wait for end of string.
s[i] ='\0'; // Terminate the string
printString("The whole received command:\r\n");
printString(s);
printString("\r\n");
// Other commands (temperature, relay control)
// REL_BTN_SIM_2
else if(strstr(s, "COMMAND:TURN_ON_I1") != NULL)
{
printString("Will set I1 on!");
output_high(PORTD, REL_BTN_SIM_2);
}
else if(strstr(s, "COMMAND:TURN_OFF_I1") != NULL)
{
printString("Will set I1 off!");
output_low(PORTD, REL_BTN_SIM_2);
}
else
printString("Unknown command.\r\n");
// Clear the buffer
memset(s,'\0', sizeof(s));
}
/* End event loop */
return (0);
}
I noticed that after I send a command around seven or eight times (or more), the serial communication is interrupted or that the command is executed with a delay. I can also see, that the debug strings "Will set I1 off!", "Will set I1 on!" are printed, but the state of the outputs are not changed (or are changed with a delay of a couple of seconds).
I was wondering if someone would know, what I'm doing wrong?
Thanks.
You have a nice definition of set_output(), but you are not using it. So I suspect that you never enabled the output driver. By setting the port register, you just enable the weak pull-up. Maybe that is not strong enough to switch on your relay driver fast. Do you have a capacitor in that driver circuit?

Read status of FT245RL pins

Sorry for my ignorance but I am very new in FTDI chip Linux software development.
I have module based on FT245RL chip, programmed to be 4 port output (relays) and 4 port opto isolated input unit.
I found out in Internet program in C to turn on/off relays connected to outputs D0 to D3. After compiling it works properly. Below draft of this working program:
/* switch4.c
* # gcc -o switch4 switch4.c -L. -lftd2xx -Wl,-rpath,/usr/local/lib
* Usage
* # switch4 [0-15], for example # switch4 1
* */
#include <stdio.h>
#include <stdlib.h>
#include "./ftd2xx.h"
int main(int argc, char *argv[])
{
FT_STATUS ftStatus;
FT_HANDLE ftHandle0;
int parametr;
LPVOID pkod;
DWORD nBufferSize = 0x0001;
DWORD dwBytesWritten;
if(argc > 1) {
sscanf(argv[1], "%d", ¶metr);
}
else {
parametr = 0;
}
FT_SetVIDPID(0x5555,0x0001); // id from lsusb
FT_Open(0,&ftHandle0);
FT_SetBitMode(ftHandle0,15,1);
pkod=&parametr;
ftStatus = FT_Write(ftHandle0,pkod,nBufferSize,&dwBytesWritten);
ftStatus = FT_Close(ftHandle0);
}
My question is. How can I read in the same program, status of D4 to D7 pins, programmed as inputs? I mean about "printf" to stdout the number representing status (zero or one) of input pins (or all input/output pins).
Can anybody help newbie ?
UPDATE-1
This is my program with FT_GetBitMode
// # gcc -o read5 read5.c -L. -lftd2xx -Wl,-rpath,/usr/local/lib
#include <stdio.h>
#include <stdlib.h>
#include "./ftd2xx.h"
int main(int argc, char *argv[])
{
FT_STATUS ftStatus;
FT_HANDLE ftHandle0;
UCHAR BitMode;
FT_SetVIDPID(0x5555,0x0001); // id from lsusb
ftStatus = FT_Open(0,&ftHandle0);
if(ftStatus != FT_OK) {
printf("FT_Open failed");
return;
}
FT_SetBitMode(ftHandle0,15,1);
ftStatus = FT_GetBitMode(ftHandle0, &BitMode);
if (ftStatus == FT_OK) {
printf("BitMode contains - %d",BitMode);
}
else {
printf("FT_GetBitMode FAILED!");
}
ftStatus = FT_Close(ftHandle0);
}
But it returns "FT_GetBitMode FAILED!" instead value of BitMode
FT_GetBitMode returns the instantaneous value of the pins. A single byte will be
returned containing the current values of the pins, both those which are inputs and
those which are outputs.
Source.
Finally I found out whats going wrong. I used incorrect version of ftdi library. The correct version dedicated for x86_64 platform is located here:
Link to FTDI library

Driving Beaglebone GPIO through /dev/mem

I'm trying to write a C program for blinking a LED on the Beaglebone. I know I can use the sysfs way...but I'd like to see if it is possible to get the same result mapping the physical address space with /dev/mem.
I have a header file, beaglebone_gpio.h wit the following contents:
#ifndef _BEAGLEBONE_GPIO_H_
#define _BEAGLEBONE_GPIO_H_
#define GPIO1_START_ADDR 0x4804C000
#define GPIO1_END_ADDR 0x4804DFFF
#define GPIO1_SIZE (GPIO1_END_ADDR - GPIO1_START_ADDR)
#define GPIO_OE 0x134
#define GPIO_SETDATAOUT 0x194
#define GPIO_CLEARDATAOUT 0x190
#define USR0_LED (1<<21)
#define USR1_LED (1<<22)
#define USR2_LED (1<<23)
#define USR3_LED (1<<24)
#endif
and then I have my C program, gpiotest.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "beaglebone_gpio.h"
int main(int argc, char *argv[]) {
volatile void *gpio_addr = NULL;
volatile unsigned int *gpio_oe_addr = NULL;
volatile unsigned int *gpio_setdataout_addr = NULL;
volatile unsigned int *gpio_cleardataout_addr = NULL;
unsigned int reg;
int fd = open("/dev/mem", O_RDWR);
printf("Mapping %X - %X (size: %X)\n", GPIO1_START_ADDR, GPIO1_END_ADDR, GPIO1_SIZE);
gpio_addr = mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR);
gpio_oe_addr = gpio_addr + GPIO_OE;
gpio_setdataout_addr = gpio_addr + GPIO_SETDATAOUT;
gpio_cleardataout_addr = gpio_addr + GPIO_CLEARDATAOUT;
if(gpio_addr == MAP_FAILED) {
printf("Unable to map GPIO\n");
exit(1);
}
printf("GPIO mapped to %p\n", gpio_addr);
printf("GPIO OE mapped to %p\n", gpio_oe_addr);
printf("GPIO SETDATAOUTADDR mapped to %p\n", gpio_setdataout_addr);
printf("GPIO CLEARDATAOUT mapped to %p\n", gpio_cleardataout_addr);
reg = *gpio_oe_addr;
printf("GPIO1 configuration: %X\n", reg);
reg = reg & (0xFFFFFFFF - USR1_LED);
*gpio_oe_addr = reg;
printf("GPIO1 configuration: %X\n", reg);
printf("Start blinking LED USR1\n");
while(1) {
printf("ON\n");
*gpio_setdataout_addr= USR1_LED;
sleep(1);
printf("OFF\n");
*gpio_cleardataout_addr = USR1_LED;
sleep(1);
}
close(fd);
return 0;
}
The output is:
Mapping 4804C000 - 4804DFFF (size: 1FFF)
GPIO mapped to 0x40225000
GPIO OE mapped to 40225134
GPIO SEDATAOUTADDR mapped to 0x40225194
GPIO CLEARDATAOUTADDR mapped to 0x40225190
GPIO1 configuration: FE1FFFFF
GPIO1 configuratino: FE1FFFFF
Start blinking LED USR1
ON
OFF
ON
OFF
...
but I can't see the led blinking.
As you can see from the output of the program the configuration is correct, FE1FFFFF,
is coherent since GPIO1_21, GPIO1_22, GPIO1_23 and GPIO1_24 are configured as outputs,
each one driving a LED.
Any idea about the reason?
Be careful. This works at first blush, but it directly writes to a register that the GPIO controller driver believes it owns. It will cause odd and hard to track down side effects, either on this GPIO line or on a GPIO that is in the same bank. For this to work reliably you need to disable the entire bank from the kernel GPIO driver.
The fix is:
pio_addr = mmap(0, GPIO1_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1_START_ADDR);
The code shown in the original post does not work with the latest Beaglebone Black and its associated 3.12 kernel. The control register offsets appear to have changed; the following code is verified to work properly:
#define GPIO0_BASE 0x44E07000
#define GPIO1_BASE 0x4804C000
#define GPIO2_BASE 0x481AC000
#define GPIO3_BASE 0x481AE000
#define GPIO_SIZE 0x00000FFF
// OE: 0 is output, 1 is input
#define GPIO_OE 0x14d
#define GPIO_IN 0x14e
#define GPIO_OUT 0x14f
#define USR0_LED (1<<21)
#define USR1_LED (1<<22)
#define USR2_LED (1<<23)
#define USR3_LED (1<<24)
int mem_fd;
char *gpio_mem, *gpio_map;
// I/O access
volatile unsigned *gpio;
static void io_setup(void)
{
// Enable all GPIO banks
// Without this, access to deactivated banks (i.e. those with no clock source set up) will (logically) fail with SIGBUS
// Idea taken from https://groups.google.com/forum/#!msg/beagleboard/OYFp4EXawiI/Mq6s3sg14HoJ
system("echo 5 > /sys/class/gpio/export");
system("echo 65 > /sys/class/gpio/export");
system("echo 105 > /sys/class/gpio/export");
/* open /dev/mem */
if ((mem_fd = open("/dev/mem", O_RDWR|O_SYNC) ) < 0) {
printf("can't open /dev/mem \n");
exit (-1);
}
/* mmap GPIO */
gpio_map = (char *)mmap(
0,
GPIO_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED,
mem_fd,
GPIO1_BASE
);
if (gpio_map == MAP_FAILED) {
printf("mmap error %d\n", (int)gpio_map);
exit (-1);
}
// Always use the volatile pointer!
gpio = (volatile unsigned *)gpio_map;
// Get direction control register contents
unsigned int creg = *(gpio + GPIO_OE);
// Set outputs
creg = creg & (~USR0_LED);
creg = creg & (~USR1_LED);
creg = creg & (~USR2_LED);
creg = creg & (~USR3_LED);
// Set new direction control register contents
*(gpio + GPIO_OE) = creg;
}
int main(int argc, char **argv)
{
io_setup();
while (1) {
// Set LEDs
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) | USR0_LED;
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) | USR1_LED;
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) | USR2_LED;
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) | USR3_LED;
sleep(1);
// Clear LEDs
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) & (~USR0_LED);
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) & (~USR1_LED);
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) & (~USR2_LED);
*(gpio + GPIO_OUT) = *(gpio + GPIO_OUT) & (~USR3_LED);
sleep(1);
}
return 0;
}
I post this here as it appears that mmap-ed access stopped working around the 3.8 kernel, and no one has posted a working solution since then. I had to reverse-engineer the control register offsets using the /sys/class/gpio interface; I hope this answer reduces some of the frustration associated with using the BeagleBone GPIOs with the newer kernels.
The code is licensed under a BSD license--feel free to use it wherever.
EDIT: user3078565 is correct in his answer above. You will need to disable the default user LED GPIO drivers either by setting their triggers to none or by completely hiding them from the kernel via editing the device tree. Failure to do this will result in the LEDs flashing as they are supposed to, but also occasionally having their states overridden by the kernel GPIO driver.
This was not an issue for my original application as it uses GPIO bank 0, which is largely ignored by the kernel GPIO drivers.
You might also need to enable the clock for any piece of hardware you are trying to control in user-space. Fortunately, you can use dev/mem and mmap() to fiddle with the clock control register for your particular piece of hardware, like this code I wrote to enable SPI0:
(define values are all from spruh73i.pdf register descriptions)
#define CM_PER_BASE 0x44E00000 /* base address of clock control regs */
#define CM_PER_SPI0_CLKCTRL 0x4C /* offset of SPI0 clock control reg */
#define SPIO_CLKCTRL_MODE_ENABLE 2 /* value to enable SPI0 clock */
int mem; // handle for /dev/mem
int InitSlaveSPI(void) // maps the SPI hardware into user space
{
char *pClockControl; // pointer to clock controlregister block (virtualized by OS)
unsigned int value;
// Open /dev/mem:
if ((mem = open ("/dev/mem", O_RDWR | O_SYNC)) < 0)
{
printf("Cannot open /dev/mem\n");
return 1;
}
printf("Opened /dev/mem\n");
// map a pointer to the clock control block:
pClockControl = (char *)mmap(0, 4096, PROT_READ|PROT_WRITE, MAP_SHARED, mem, CM_PER_BASE);
if(pClockControl == (char *)0xFFFFFFFF)
{
printf("Memory map failed. error %i\n", (uint32_t)pClockControl);
close( mem );
return 2;
}
value = *(uint32_t *)(pClockControl + CM_PER_SPI0_CLKCTRL);
printf("CM_PER_SPI0_CLKCTRL was 0x%08X\n", value);
*(uint32_t *)(pClockControl + CM_PER_SPI0_CLKCTRL) = SPIO_CLKCTRL_MODE_ENABLE;
value = *(uint32_t *)(pClockControl + CM_PER_SPI0_CLKCTRL);
printf("CM_PER_SPI0_CLKCTRL now 0x%08X\n", value);
munmap( pClockControl, 4096 ); // free this memory map element
Once I have executed this code fragment, I can access SPI0 registers using another mmap() pointer. If I don't enable the SPI0 module clock first, then I get a bus error when I try to access those SPI registers. Enabling the clock is persistent: Once enabled this way it stays on until you disable it, or maybe until you use the spidev and then close it, or reboot. So if your application is finished with the hardware you enabled, you might want to disable it to save power.
for enable GPIO banks....
enableClockModules () {
// Enable disabled GPIO module clocks.
if (mapAddress[(CM_WKUP_GPIO0_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK) {
mapAddress[(CM_WKUP_GPIO0_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] |= MODULEMODE_ENABLE;
// Wait for the enable complete.
while (mapAddress[(CM_WKUP_GPIO0_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK);
}
if (mapAddress[(CM_PER_GPIO1_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK) {
mapAddress[(CM_PER_GPIO1_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] |= MODULEMODE_ENABLE;
// Wait for the enable complete.
while (mapAddress[(CM_PER_GPIO1_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK);
}
if (mapAddress[(CM_PER_GPIO2_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK) {
mapAddress[(CM_PER_GPIO2_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] |= MODULEMODE_ENABLE;
// Wait for the enable complete.
while (mapAddress[(CM_PER_GPIO2_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK);
}
if (mapAddress[(CM_PER_GPIO3_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK) {
mapAddress[(CM_PER_GPIO3_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] |= MODULEMODE_ENABLE;
// Wait for the enable complete.
while (mapAddress[(CM_PER_GPIO3_CLKCTRL - MMAP_OFFSET) / GPIO_REGISTER_SIZE] & IDLEST_MASK);
}
}
Where...
MMAP_OFFSET = 0x44C00000
MMAP_SIZE = 0x481AEFFF - MMAP_OFFSET
GPIO_REGISTER_SIZE = 4
MODULEMODE_ENABLE = 0x02
IDLEST_MASK = (0x03 << 16)
CM_WKUP = 0x44E00400
CM_PER = 0x44E00000
CM_WKUP_GPIO0_CLKCTRL = (CM_WKUP + 0x8)
CM_PER_GPIO1_CLKCTRL = (CM_PER + 0xAC)
CM_PER_GPIO2_CLKCTRL = (CM_PER + 0xB0)
CM_PER_GPIO3_CLKCTRL = (CM_PER + 0xB4)
I have written a small library that perhaps you might be interested. At the moment only works with digital pins.
Regards
REF: madscientist159
// OE: 0 is output, 1 is input
#define GPIO_OE 0x14d
#define GPIO_IN 0x14e
#define GPIO_OUT 0x14f
should be
// OE: 0 is output, 1 is input
#define GPIO_OE 0x4d
#define GPIO_IN 0x4e
#define GPIO_OUT 0x4f
unsigned int offset address derived from the unsigned char address
This anomaly appears to be an artifact of incomplete address decoding in the AM335x chip. It makes sense that 0x4D, 0x4E, and 0x4F work as offsets from the base address for accessing these registers. C/C++ pointer arithmetic multiplies these offsets by 4 to produce true offsets of 0x134, 0x138, and 0x13C. However a 'shadow' copy of these registers can be accessed through 0x14D, 0x14E, and 0x14F. I have verified that both sets of offsets work. I didn't bother trying 0x24D etc.
The GPIO_CLEARDATAOUT register can be accessed using offset 0x64 and the GPIO_SETDATAOUT register can be accessed using offset 0x65.