Forth Lesson 22: Difference between revisions
(Added twsi and accelerometer stuff) |
|||
Line 244: | Line 244: | ||
| mmap |
| mmap |
||
| ( phys-addr size -- virt-addr ) |
| ( phys-addr size -- virt-addr ) |
||
| Assigns a virtual address to a physical device address |
| Assigns a page-aligned virtual address to a physical device address range |
||
| d4050000 1000 mmap constant clock-unit-base |
| d4050000 1000 mmap constant clock-unit-base |
||
|- |
|||
| unaligned-mmap |
|||
| ( phys-addr -- virt-addr ) |
|||
| Assigns a possibly-unaligned virtual address to a physical device address |
|||
| d4033800 unaligned-mmap constant twsi5-base |
|||
|} |
|} |
||
For mmap, the physical address and size must both be multiples of 0x1000 (the CPU page size), i.e. their low three hex digits must be 0. |
|||
For unaligned-mmap, the physical address need not be page-aligned. Unaligned-mmap calls mmap with a page-aligned address (mapping a single page) and then adds the offset into the virtual address. |
|||
You can add offsets to the virtual address to access registers within the range {virtual-address .. virtual-address+size-1}. For example: |
You can add offsets to the virtual address to access registers within the range {virtual-address .. virtual-address+size-1}. For example: |
||
Line 254: | Line 261: | ||
ok d4050000 1000 mmap constant clock-unit |
ok d4050000 1000 mmap constant clock-unit |
||
ok clock-unit 24 + l@ . |
ok clock-unit 24 + l@ . |
||
You could use unaligned-mmap to get an address that points to an individual register within a register block, but it's usually better to map the base address of the register block and then apply small offsets to the virtual address to access individual registers. |
Revision as of 21:16, 23 May 2011
Using Forth Under Linux
You can run Forth under Linux and use it to inspect I/O devices.
On XO-1.75
Get http://dev.laptop.org/~wmb/sdkit-arm.tgz . Unpack it into your home directory on an XO-1.75 .
$ tar xfz sdkit-arm.tgz
Then:
$ cd sdkit-arm $ sudo -s # ./sdkit.sh ok
sdkit comes up in hex mode, so you can enter and display numbers in hex without additional qualifiers. To enter a decimal number, precede it with "d# ", e.g. "d# 123"
GPIO Access
Command | Stack | Description | Example |
---|---|---|---|
gpio-pin@ | ( gpio# -- flag ) | Flag is true if GPIO pin is high | d# 108 gpio-pin@ . |
gpio-out? | ( gpio# -- flag ) | Flag is true if GPIO is an output | d# 108 gpio-out? . |
gpio-set | ( gpio# -- ) | Drives GPIO high | d# 108 gpio-set |
gpio-clr | ( gpio# -- ) | Drives GPIO low | d# 108 gpio-clr |
gpio-rise@ | ( gpio# -- flag ) | Flag is true if rising edge detected | d# 108 gpio-rise@ . |
gpio-fall@ | ( gpio# -- flag ) | Flag is true if falling edge detected | d# 108 gpio-fall@ . |
gpio-edge@ | ( gpio# -- flag ) | Flag is true if edge detected | d# 108 gpio-edge@ . |
gpio-clr-edge | ( gpio# -- ) | Clears GPIO edge detector | d# 108 gpio-clr-edge |
gpio-dir-out | ( gpio# -- ) | Sets GPIO direction to output | d# 108 gpio-dir-out |
gpio-dir-in | ( gpio# -- ) | Sets GPIO direction to input | d# 108 gpio-dir-out |
gpio-set-rer | ( gpio# -- ) | Enables rising edge detection | d# 108 gpio-set-rer |
gpio-clr-rer | ( gpio# -- ) | Disables rising edge detection | d# 108 gpio-set-rer |
gpio-set-fer | ( gpio# -- ) | Enables falling edge detection | d# 108 gpio-set-fer |
gpio-clr-fer | ( gpio# -- ) | Disables falling edge detection | d# 108 gpio-set-fer |
Multi-Function Pin Register Access
The Multi-Function Pin Registers (MFPRs) control the assignment of chip pins to internal functions, and also control characteristics of those pins, such as drive strength, pull up/down resistors, etc. Since each multi-function pins can be used as a GPIO, we use the GPIO number to designate which pin we are interested in.
Command | Stack | Description | Example |
---|---|---|---|
af@ | ( gpio# -- function ) | Returns the MFPR setting for gpio# | d# 108 af@ . |
af! | ( function gpio# -- ) | Sets the MFPR for gpio# | h# a0c0 d# 108 af! |
dump-mprs | ( -- ) | Displays a table of all MFPR settings | dump-mfprs |
gpio>mfpr | ( gpio# -- address ) | Returns the address of the MFPR register for gpio# | d# 108 gpio>mfpr . |
Camera Test
The camera test turns on the camera chip and lets you access internal camera chip registers via its I2C bus interface.
Command | Stack | Description | Example |
---|---|---|---|
test-camera-i2c | ( -- ) | Turns on the camera and dumps its internal registers | test-camera-i2c |
start-camera | ( -- ) | Sets up the camera clocks and pads, powers on and resets the camera sensor chip | start-camera |
ov@ | ( reg# -- value ) | Reads an internal camera register via I2C | 5 ov@ . |
ov! | ( value reg# -- ) | Writes an internal camera register via I2C | 4 12 ov! |
ov-dump | ( -- ) | Displays a bunch of camera registers | ov-dump |
Accelerometer
Command | Stack | Description | Example |
---|---|---|---|
select /accelerometer | ( -- ) | Activate accelerometer device driver | select /accelerometer |
acceleration@ | ( -- x y z ) | Read acceleration values | acceleration@ .d .d .d acceleration@ .d .d .d cr many |
unselect | ( -- ) | Deactivate the current device driver | unselect |
Two-Wire Serial Interface (I2C/SMBUS) Hardware
Command | Stack | Description | Example |
---|---|---|---|
set-twsi-target | ( slave channel -- ) | Select a TWSI channel and slave address for subsequent access | h# 3a 6 set-twsi-target |
twsi-b@ | ( reg -- byte ) | Read a byte | h# 20 twsi-b@ . |
twsi-b! | ( byte reg -- byte ) | Write a byte | h# 47 h# 20 twsi-b! |
twsi-write | ( byte_n-1 .. byte0 n -- ) | Write n bytes from the stack | 33 22 11 00 4 twsi-write |
twsi-get | ( reg#_n-1 .. reg#0 #reg-bytes #data-bytes -- data_n-1 .. data0 ) | Send #reg-bytes register address bytes from the stack, then read #data-bytes onto the stack. | h# 23 h# 01 2 4 twsi-get . . . . |
Accessing Arbitrary Devices
In addition to the "canned" access words for specific devices, you can manually access any device you wish, using the "mmap" command to assign a virtual address to the I/O device's physical address.
Command | Stack | Description | Example |
---|---|---|---|
mmap | ( phys-addr size -- virt-addr ) | Assigns a page-aligned virtual address to a physical device address range | d4050000 1000 mmap constant clock-unit-base |
unaligned-mmap | ( phys-addr -- virt-addr ) | Assigns a possibly-unaligned virtual address to a physical device address | d4033800 unaligned-mmap constant twsi5-base |
For mmap, the physical address and size must both be multiples of 0x1000 (the CPU page size), i.e. their low three hex digits must be 0.
For unaligned-mmap, the physical address need not be page-aligned. Unaligned-mmap calls mmap with a page-aligned address (mapping a single page) and then adds the offset into the virtual address.
You can add offsets to the virtual address to access registers within the range {virtual-address .. virtual-address+size-1}. For example:
ok d4050000 1000 mmap constant clock-unit ok clock-unit 24 + l@ .
You could use unaligned-mmap to get an address that points to an individual register within a register block, but it's usually better to map the base address of the register block and then apply small offsets to the virtual address to access individual registers.