Accessing mapped GPIO in gcc?
Pages: 1 2
Tristan M. (2946) 1039 posts |
I’ve been trying to work out how to control the GPIO pins on my Pi3 using gcc and OSLib. I want to avoid assembler even if it isn’t the most efficient route. I just want to put together something that I can base a library off that I can use for my own projects. |
Rick Murray (539) 13840 posts |
You are probably needing to access the I/O in SVC mode. That’s what the OS_EnterOS is for. |
Jeffrey Lee (213) 6048 posts |
If you do decide to use OS_EnterOS/OS_LeaveOS, doing it from assembler is pretty much the only way. If you were to try using them from C then things would go wrong pretty quickly due to the switch from the USR stack to the SVC stack. |
Tristan M. (2946) 1039 posts |
Rick Murray: My library as in the one that I am using (OSLib) or what I intend to write? If you mean mine, it’s still just a standalone program where I’m working on getting basic hardware I/O to work. OSLib has “os_enter_os” and “os_leave_os” documented as SWIs for “OS.h”. Trouble is I can’t work out how to use them. Jeffrey Lee: Assembler is about the only way that i could potentially get to work at this point because I haven’t worked out how to use things with no params listed in the OSLib SWIs part of the StrongHelp manual. I tried as a function with no params, as a constant in swi(), swi() and kernel_swi(). It didn’t recognise them in any form. An explanation or example somewhere would have gone a long way. |
Rick Murray (539) 13840 posts |
OSLib.
They will be veneers for the appropriate SWIs. Basically:
However note the following points carefully:
What this means is you cannot just stay in SVC mode.
I cannot answer, I don’t use OSLib.
Generally things like that stay in SVC mode to try to protect the system from errant accesses. I don’t recall the specifics, but I think when I tried directly playing with the GPIO on my Pi (1), the SWI actually mapped in an entire megabyte, and just returned to me the offset to what it is that I was interested in. With this in mind, it is possible that requesting to map in the GPIO in USR mode might expose some other things.
? I’m not sure what the question is, exactly. Kernel SWI is pretty simple…
Where SWINUM is a SWI number. Nothing more, nothing less.
Generally, one should assume that application code will not work in SVC mode except for brief hops in and right back out again. For instance, at the top I said:
That is the only way it’ll work. If you have the DDE, that could be shortened down to:
Disclaimer: I’m sitting outside in the sunshine writing this on the iPad. It may or may not work. ;-) |
Steve Fryatt (216) 2105 posts |
They’re just functions, so
Except that, as the OSLib manual notes, you can’t use
No, you bitwise OR them. For example
OSLib isn’t really a library in that sense: it’s just veneers around the SWIs. Beyond getting variables in to and out of registers, there’s no extra code there. That is, |
Tristan M. (2946) 1039 posts |
Coding while sick and medicated is like driving while drunk, except nobody cares if you crash your program. Rick Murray: It wouldn’t bother me if the SWI mapped a whole megabyte, even though it shouldn’t. I’d just map 0×3F000000 instead of 0×3F200000 and set a pointer to 0xF9200000 instead of 0xF9000000 to keep things simpler. I kind of figured that the best I could hope for is a single read or write in SVC mode without causing havoc. Thing is I don’t trust gcc that much. That’s a monumental effort for typing code on an iPad or any tablet really. SwiftKey on my TF700T decided it’d try autocorrecting my typing when I was writing some code for an Arduino this afternoon. I did not appreciate that. I don’t have DDE, and probably never will. It’d be nice but I just don’t need it. If they’d kept the DDE Pascal up to date I probably would consider it. Steve Fryatt: Thanks for the clarification. It’s wgat I was hoping. Just simple wrapper libraries without extra fiddling. When I can work out which bits to pass for setting the window for USR mode, I’m going to try that. Needs a clearer head that I have right now though. I’m not too worried about clobbering other IO. My code isn’t going to be controlling a nuclear reactor or a morphine pump. I usually write things to be pretty idiot(me) proof anyway. Pass things to the magic functions by value with checking on the max and min values etc. built in. If I want fast I/O I use a microcontroller. Pi I/O is not fast but it is useful, so I’d rather the marginal speed penalty for robust code. |
Jeffrey Lee (213) 6048 posts |
Rick Murray: It wouldn’t bother me if the SWI mapped a whole megabyte, even though it shouldn’t. I’d just map 0×3F000000 instead of 0×3F200000 and set a pointer to 0xF9200000 instead of 0xF9000000 to keep things simpler. OS_Memory 13 does (currently) map in in megabyte-aligned chunks, but it’s also smart enough to re-use an existing mapping if one is present (right address + size + access permissions). So on a typical system the logical address space you lose due to overly large IO areas isn’t that significant. However it’s important not to make assumptions about any alignment/rounding that OS_Memory 13 performs – it could easily go up or down in future OS versions. |
Steve Pampling (1551) 8170 posts |
Hmmm, the current network interconnection map at work is exactly what was on the whiteboard when I came into work after a bout of flu. The writing of the annotations was mine but I have no memory of doing it. According to my colleague I mumbled a lot while drawing it out. |
Rick Murray (539) 13840 posts |
I tend to avoid medication if possible, just the odd paracetamol if necessary. My attempt at writing a 6502 emulator from the ground up in VisualBasic (!) using only the Advanced User Guide to detail the opcodes? That could only have been the result of a very muddled head. One of the main reasons I’ve dropped the project is not that I rarely touch VB these days (which is true), but rather I devised some weirdo way of reading in the instructions from memory to get around the fact that VB really isn’t designed for something like that. Maybe some day I’ll try to work out WTF it actually does!
To answer both you and Jeffrey – as he mentions, how the memory mapping actually does what it does is not our concern. What I am doing is pointing out that the granularity of mapping is rather more than “just that port”, and by setting it to have USR mode access, you’re opening up potentially other1 I/O and stuff to have the same access rights.
Hmm… 1MiB on a machine with a theoretical 4GiB addressing range, and 1GiB actually installed. Oh, and you might want to browse this thread and note things such as: The RMA is a global resource, so it will still need to be a regular dynamic area, and will still need 256MiB-ish logical address space allocating to it even though it may only have 4-16MiB of pages mapped in.
You have an assembler with GCC, right? Simply write a routine to enter SVC mode, to the read (or write), then exit from SVC mode. It might be better to use
Not so much. The iPad seems to have a learning function where it’ll wavy-line things it thinks are spelling errors (but it didn’t have suggestions for) but if you use them a few times, it’ll consider that you meant to do that. Now. Android 5, on the other hand. Miserable. Miserable. Miserable. It can’t handle CamelCase words, like most SWIs, so you get either all caps, or normal word (initial cap if it thinks it needs it). iOS understands that RISC is followed by OS and both should be capitalised. Android tends to understand that risc is followed by os, but never even attempts to set the capitalisation. Plus the Android select-copy-paste is a miserable mess where you often end up selecting everything but the text you wanted to select.
Wow. I thought I was the only one who remembered that!
For your own use, no. But if you ever plan to share your program…
Of course not. We here are all way overqualified for writing mission critical code. I feel like I ought to add a smiley, but then I read The Register so I’m not sure the statement isn’t without some measure of truth.
Indeed. It can be useful to bolt an Arduino to the Pi, so it can handle the mission critical stuff (plus it has ADC), and let it regurgitate the information to the Pi in tidy predigested chunks.2 1 Vague, as it’s been a long time since I looked at the sorry excuse that passes for a datasheet. 2 TMI? ;-) |
Tristan M. (2946) 1039 posts |
As always I had part of a reply typed but never got to finish it. Just a quick one to let you all know I haven’t given up. Just have no time. I did however just try one of Bruce Smith’s GPIO examples on the Pi3 with an LED attached. It worked, after changing the IO base address of course. It’s good to have a basic sanity check. I have to do a bit of digging to find a better example of asasm inline with GCC. The included example just didn’t have enough for me to work from. |
Tristan M. (2946) 1039 posts |
Sorry. Another real short one.
This was caused by this rather awful looking two lines of inline asm
For some reason StrongED isn’t letting me put tabs in, so I had to use the escape character for it. It’s not choking on that anyway. Have I embarked on a fool’s errand here? Also, while GCC seems to understand _kernel_swi(…)it doesn’t seem to know _kernel_swi_regswhich is a bit weird. Perhaps they call it something different? It’s a bit of a pain because I don’t know how the struct is defined so I can’t just roll my own with certainty it’ll behave. |
Jeffrey Lee (213) 6048 posts |
Most likely you’re missing swis.h contains the definitions for all the SWI numbers; they’re all #defines so the names will get replaced by numbers before the C compiler/inline assembler gets a proper look in. But by not including the file, the string is left in place, causing the inline assembler to think that it’s a symbol name. But symbol resolution generally involves help from the linker (e.g. resolving the values of external symbols), and the relocation format used for SWIs isn’t supported by whatever object format the inline assembler generates, so rather than getting a useful “SWI OS_EnterOS not found” error you get the rather cryptic “cannot represent SWI relocation” error. kernel.h contains the definitions of all the |
Tristan M. (2946) 1039 posts |
That’s very helpful, thanks. I didn’t include “kernel.h” Truthfully I didn’t know about it. Finding documentation has been pretty hard. I’ll try it next chance I get. Right now my Pi3 is preoccupied trying to drag the Pi Zero’s SD up to date and install the gcc toolchain. I figure a second computer with a different generation SoC would be nice to help weed out any odd inconsistencies. Updating it is so slooooow though. I think the MicroSD I’m using for the Zero must be utter rubbish. I’m still kind of sick. Whatever the bug is is more or less just making me dizzy and my mind kind of cloudy now. Just wanted to say about the 6502 emulator written in VB, I wrote something years ago using a tiny imaginary subset of the 6502 instructions in QBASIC. It had an accompanying almost-assembler too. Next thing I’m going to try is the enter /leaveOS SWIs in an assembler file. Probably be easier just to copypaste the GCC examples for that one. |
Fred Graute (114) 645 posts |
To insert a tab character the action tied to the Tab key has to be ‘TrueTab’, in your case it probably wasn’t. The action performed by the Tab key can be changed, the options available are:
The infobar at the bottom of the window will show which action is currently set. You can change it by clicking on the infobar field or by using Ctrl-Tab. |
Tristan M. (2946) 1039 posts |
As always, at least v2 of my reply. Thanks for the help, Fred! FOr some reason that one file had it’s tabs set weird. I probably grabbed the wrong mouse and clicked. The PC and Pi share the desk and one of the monitors. I’m just going to dump a slightly cleaned up version of the mess I have here. This is the first one that doesn’t explode in flames. It also doesn’t light up the LED on GPIO21 :(
edit: Just spotted one thing. The byte offset to get to GPSEL2 should have been 8, not 4. |
Jeffrey Lee (213) 6048 posts |
It looks like there are a couple of pointer-related pitfalls that you’ve fallen into. Firstly: //reg.r[1] = *p_GPIO_phys_addr; //PI 3 GPIO base address. reg.r[1] = 0x3F200000;
If you change it to this then it will work, i.e. put the value 0×3F200000 into R1: reg.r[1] = p_GPIO_phys_addr; //PI 3 GPIO base address. However the compiler might throw a warning about a type mismatch (p_GPIO_phys_addr is a byte pointer but regs.r1 will be an int). You can either ignore the warning, insert a type cast (e.g. So the way I’d fix the warning would be: const unsigned int p_GPIO_phys_addr = 0x3F200000 Secondly:
Yes, the byte offset should be 8. But when you add an offset to a C pointer, you don’t specify the offset in terms of bytes – you specify it in terms of the size of the type being pointed to. So if you have a pointer A lot of code I’ve seen for accessing memory-mapped IO in C tends to do it in one of two ways: define a struct which has the same memory layout as the hardware (pros: increased type safety, cons: easy to make mistakes in the struct definition and have everything offset incorrectly), or use #defines to define all the offsets and use wrapper functions/macros for the memory accesses (so you can e.g. use byte offsets in the #defines and the wrapper function will take care of any math or typecasts which are used to ensure it gets treated as a byte offset when it’s applied to the base pointer). And finally a non-pointer thing: //I don't like this line. Shouldn't it be '|'? reg.r[0] = 13 + (1 << 17); // usr permission + osmemory_map_in_permanent_io?
|
Tristan M. (2946) 1039 posts |
Ooh. You’ve spotted some things I haven’t. I only just saw your post but I’ll post a new version of what I’ve been working on. Chunks of dead commented code etc. have been stripped out for posting. The goofed address dereferencing at the beginning was commented out for a reason. But what was it… It may have been something to do with using the OSLib call initially. Really I just stuck the magic number in to give me one less thing to worry about for the time. I have to agree with you with using a struct or defines etc. with a wrapper. I know for a fact this code will not scale. It’s not meant to. The sole purpose is to initialize pin 21 and set it high. When I see that result I will take what has been learned and write something useful. It’s getting this bit to work that is the stumbling block for me. Anyhow this is what I have.
|
Tristan M. (2946) 1039 posts |
I had a bit of a mishap with building which has unintentionally given me some info. So far I’ve been using my pi 3 to work on this. Getting the GCC toolchain working on the Zero was a headache for some reason, so I cloned the Pi3’s SD on to one for the zero, tweaked the settings and booted it. Everything works fine (except setting to the wrong initial resolution again). Apparently I was. I just saw it right now. I’m over the bug I caught and my head is clearer. Jeffrey, for some reason I wasn’t interpreting what you wrote correctly. My math is off for the registers. I’ll fiddle with it later. e: Changed the offset to 32 bit words, ie divided the memory offsets by 4 that I was using, and it worked first go. I feel like such a dummy! Thanks for the help! |
Tristan M. (2946) 1039 posts |
Only had minutes here and there to play with this. After tweaking my GPIO “Hello World” to let me enable PWM pins for sound on the Pi Zero I started to extend it a little to make it easier to use. I’m giving it Arduino style functions because they are pretty ubiquitous. Last night I knocked together pinMode(pin, mode) with bounds checking for pin# and support for INPUT, OUTPUT, and ALT0 – ALT5 |
Tristan M. (2946) 1039 posts |
I’ve done a little more but it’s not entirely why I’m here. It’s because I learned something Pi3 specific. http://raspberrypi.stackexchange.com/questions/45570/how-do-i-make-serial-work-on-the-raspberry-pi3 It’s a thread about the UARTs on the Pi3. It answers a few questions for me. *The main UART is connected to the Bluetooth chip. *Pins 8 and 10 on the GPIO header are the Mini UART. *The Mini UART is dependent on system clock speed. Lucky I have USB to logic level serial modules with a couple of different chipsets and a USB to RS232 dongle I guess. At least SPI and I2C should still be fine. e: I was just having a look at the datasheet for the BCM43438 module that stole my precious pins. It has a builtin ARM Cortex M3. The Pi 3 just keeps getting weirder. |
Jeffrey Lee (213) 6048 posts |
It’s a thread about the UARTs on the Pi3. It answers a few questions for me. However that’s not the full story. If you’re not using bluetooth you can change the pin mux settings and connect the main UART back up to the standard UART GPIO pins. That’s what RISC OS currently does.
They’re Linux specific. The firmware does process the files (it merges them together, and perhaps makes other tweaks dependent on config.txt settings) but AIUI the firmware doesn’t set up any of the hardware to match what’s specified in the device tree/overlays – it leaves all of that to the OS.
Having a microprocessor in bluetooth/wifi modules is pretty standard. I’m not sure how it is with USB dongles, but for on-board stuff the host OS generally has to upload a firmware blob to the chip which contains the code the microprocessor will run. |
Tristan M. (2946) 1039 posts |
Oh good! I didn’t know the standard UART was set as active in RISC OS with the Pi 3. That’s going to be a big help. I’m getting a bit confused about the overlays now. I guess there’s some low level stuff built into one of the files on the boot partition too, like changing the PWM audio pins. I had to use that dtoverlay line to get the audio to work on the Pi Zero. At least I believe I did. I might try commenting out the line then just changing the pin mode in RISC OS via the program I’m working on. I wasn’t expecting such a fully formed CPU in the WiFi / BT chip. The datasheet did give a tiny glimmer of hope for the chip being usable at some point at least. Truth be told I was hoping to be way further ahead on this project than I am. Finding a way to access the GPIO via GCC was a royal pain. I was hoping to enter something in the Raspberry Pie contest months ago for the chance to win a better supported Pi so I don’t need the program I’m writing to access GPIO hahaha! Never mind. I’ll just keep going anyway. An Arduino like interface that works with GCC in RISC OS might attract a few people that have been on the fence about trying RISC OS. |
Rick Murray (539) 13840 posts |
That’s the problem with hardware that is “barely documented” at best. Your BT/WiFi will have its own SoC that will be running a proper operating system. Not like Linux, an RTOS of some sort. |
Tristan M. (2946) 1039 posts |
There were still black boxes in the eighties, however they were easier to pry open. Metaphorically speaking. I’m not sure I’m meant to have the datasheet for the module. Unless they didn’t update it to reflect it’s public release nature. |
Pages: 1 2