Recently, a colleague asked if I could help with a project that required an I2C bus. This technology is nothing new to me, but his request came with a twist: it needed to be done on a Beaglebone. Well, I couldn't deny this opportunity because I too had a similar project that requested very much the same setup.
I quick bit of surfing surprisingly turned up dry results - most of which were examples in Python. (Why not Ruby?!) Anyway, after several hours of research I finally managed to uncover some valuable hits...
First things first! In order to use I2C one must start up it's engine(s). This is done by entering the following shell command: (There may be two more capes for the other buses, however this is the only one I could find in /lib/firmware; For distros such as Angstrom, I2C should already be loaded)
echo BB-I2C1 > /sys/devices/bone_capemgr.*/slots
REGISTERS
To access i2c registers, the interface clock [ICLK] first needs to be un-gated. This can be done through the Power, Reset, and Clock Management [PRCM] module registers: CM_PER_L4LS_CLKSTCTRL & CM_PER_I2C_CLKCTRL. For this demonstration, the code from the git repository BoneMemory is used - load the shell script with "source script.sh" command.
# Enable I2C2 ICLK and FCLK - otherwise 'Bus Error'
writem 0x44E00000 0 0 # CM_PER_L4LS_CLKSTCTRL.MODULCTRL = 0
writem 0x44E00000 50 2 # CM_PER_I2C2_CLKCTRL = 2
# Prepare bus data and begin
writem 0x4819C000 98 1 # I2C_CNT = 1
writem 0x4819C000 9C F # I2C_DATA = 0x0F
writem 0x4819C000 A4 8C03 # EN/MASTER/TX/START/STOP
See Pg 3715 of the Technical Reference Manual for a detailed approach to reading and writing via registers.
BASH
(I2C devices are assigned according to the order they were initialized so $Bus=1 may be the I2C-2 bus. Confirm you are using the correct bus by listing them:
"ls -l /sys/bus/i2c/devices"
I2C0 = 0x44E0B000, I2C1 = 0x4802A000, I2C2 = 0x4819C000)
Next is the handy dandy tool that will automagically bit-bang for you to find all connected devices on the given bus: (UU is a reserved address)
i2cdetect -y -r $Bus
To view all the bit values stored in a slave's register file (EE/PROM), one can call:
i2cdump -y $Bus $Addr
To get a particular byte value from the slave's register file, use:
i2cget -y $Bus $Addr $Offset
# Example: i2cget -y 1 0x77 0xB2 w - read a word from 0x77B2
And to write to the register (if permitted by the slave), use:
i2cset -y $Bus $Addr $Offset $Value
# Example: i2cset -y 0 0x52 0x02 0xFF - write 0xFF to 0x5202
These are all script values, but at the same time my priority was set on doing all this in C/C++ and I really didn't want to use the 'system()' function. I knew from my experience with other elements including PWM and GPIO, that there are files one can access in a lower level language such as C that would allow me this I2C functionality, and, after a 45 min presentation (v=8C2zk6B-eLU), I was correct!
The files are located in /dev: i2c-0, i2c-1, & i2c-2
- - - - - - - - - - - - - - - - -
I've tested both the registry and bash approaches with great success!
Friday, May 16, 2014
Wednesday, April 16, 2014
BeagleBone Device Tree Overlays
(All commands and tests were performed in Debian Wheezy, though in most cases, should also work in various other Linux Distro's)
Real quickly, what is a device tree [DT] overlay? Well, just like a .config file - such as those used in Minecraft Mods - a device tree overlay describes how the kernel is wired in order to take advantage of any new hardware peripherals dynamically - in the case of the bone, it is most commonly used to describe which pins are wire to what device and who has compatibility.
Let's review over the structure of a simple device tree: (Thanks to Adafruit for their valuable detailing)
Unfortunately, Debian and several other distros do not come with device tree source files, just the compiled blobs. This was unfortunate for me as I had four Debian-imaged bones and one Angstrom bone that I forgot the login info to... after several hours I managed to reimage the Angstrom copy to see if the source files were even there, and thankfully they were!
EDIT: While browsing through the raw Linux Kernel source code, I found a number of other *.dts files linking to many other devices. To find specific names and values for these trees, the kernel tree its self has all the answers - it may be intimidating at first but really I feel it is no different from Minecraft: Kernel=Vanilla, Drivers=Mods, Hardware Descriptors=Config Files. The Beaglebone Black uses an OMAP3 [OMAP3630] microprocessor also references as AM33XX in the source code. Linux Source Code
This is the version of the DT, which is 'version 1'
/dts-v1/;
This comes next, tagging the DT as a plugin
/plugin/;
Without specifying compatibility, this plugin would not work
compatible = "ti,beaglebone", "ti,beaglebone-black";
Next is the identification, including the DT name and version - which seems to always be '00A0' (this is also the name of the file in the form NAME-VERSION.dtbo)
part-number = "BB-BONE-DT-NAME";
version = "00A0";
Include any and all resources to be used. (In some cases, just the pins are enough, otherwise it is always good to include the device the pins will be muxed to as well) Here the pin is specified in the form HEADER.PIN, the first pru will also be used:
exclusive-use = "P9.27", "pru0";
And finally the fragments, which can be seen as partitions, or 'structs' in a c-stylized way of looking at things. A device tree can have as many fragments as it needs, but for the simplest layouts, one only needs two: the first for pin muxing and the second for device initialization and pin binding. The syntax goes as follows: fragment@NUM { }; so fragment@0 {}; or fragment@2 {};
A fragment will begin with a target, followed by the __overlay__ block, and within that block resides the settings to be applied to or through the targeted device. For example:
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
token_name: sub_name {
pinctrl-single,pins = <
0x1a4 0x25
>;
};
};
};
The target is am33xx_pinmux and through the target via 'pinctrl-single,pins,' pin P9.27(0x1a4) is muxed to pin mode 5 as a 'fast-input' with an internal pull-down (0x25) - this prepares the pins for PRU0 output. The 'token_name:' is referenced in other fragments further down.
When initializing a device in the device tree, one must set the status to 'okay.' Then in order to do anything with that device, one must assign the pins created earlier:
fragment@2 {
target = <&pruss>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&token_name>;
};
};
The pin names can be left as 'default.' Sometimes there are other names that can be added for state manipulation such as found in the source file: cape-boneblack-hdmi-00A0.dts: pinctrl-names = "default", "off"; which can be seen in action through shell:
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
default
# echo off > /sys/devices/ocp.*/hdmi.*/pinmux_state
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
off
# echo "test" > /sys/devices/ocp.*/hdmi.*/pinmux_state
-sh: echo: write error: No such device
The following is a list of devices that can be modified or used via device tree overlays:
To compile the source, run the following shell command:
dtc -O dtb -o $NAME-$VERSION.dtbo -b 0 -@ $NAME-$VERSION.dts
To apply the new overlay, copy the *.dtbo file to /lib/framework and run the command:
echo $NAME > /sys/devices/bone_capemgr.*/slots
Confirm that it has loaded:
cat /sys/devices/bone_capemgr.*/slots
And to remove it, use the slot number where it is found:
echo -$SLOT_NUM > /sys/devices/bone_capemgr.*/slots
Real quickly, what is a device tree [DT] overlay? Well, just like a .config file - such as those used in Minecraft Mods - a device tree overlay describes how the kernel is wired in order to take advantage of any new hardware peripherals dynamically - in the case of the bone, it is most commonly used to describe which pins are wire to what device and who has compatibility.
Let's review over the structure of a simple device tree: (Thanks to Adafruit for their valuable detailing)
Unfortunately, Debian and several other distros do not come with device tree source files, just the compiled blobs. This was unfortunate for me as I had four Debian-imaged bones and one Angstrom bone that I forgot the login info to... after several hours I managed to reimage the Angstrom copy to see if the source files were even there, and thankfully they were!
EDIT: While browsing through the raw Linux Kernel source code, I found a number of other *.dts files linking to many other devices. To find specific names and values for these trees, the kernel tree its self has all the answers - it may be intimidating at first but really I feel it is no different from Minecraft: Kernel=Vanilla, Drivers=Mods, Hardware Descriptors=Config Files. The Beaglebone Black uses an OMAP3 [OMAP3630] microprocessor also references as AM33XX in the source code. Linux Source Code
This is the version of the DT, which is 'version 1'
/dts-v1/;
This comes next, tagging the DT as a plugin
/plugin/;
Without specifying compatibility, this plugin would not work
compatible = "ti,beaglebone", "ti,beaglebone-black";
Next is the identification, including the DT name and version - which seems to always be '00A0' (this is also the name of the file in the form NAME-VERSION.dtbo)
part-number = "BB-BONE-DT-NAME";
version = "00A0";
Include any and all resources to be used. (In some cases, just the pins are enough, otherwise it is always good to include the device the pins will be muxed to as well) Here the pin is specified in the form HEADER.PIN, the first pru will also be used:
exclusive-use = "P9.27", "pru0";
And finally the fragments, which can be seen as partitions, or 'structs' in a c-stylized way of looking at things. A device tree can have as many fragments as it needs, but for the simplest layouts, one only needs two: the first for pin muxing and the second for device initialization and pin binding. The syntax goes as follows: fragment@NUM { }; so fragment@0 {}; or fragment@2 {};
A fragment will begin with a target, followed by the __overlay__ block, and within that block resides the settings to be applied to or through the targeted device. For example:
fragment@0 {
target = <&am33xx_pinmux>;
__overlay__ {
token_name: sub_name {
pinctrl-single,pins = <
0x1a4 0x25
>;
};
};
};
The target is am33xx_pinmux and through the target via 'pinctrl-single,pins,' pin P9.27(0x1a4) is muxed to pin mode 5 as a 'fast-input' with an internal pull-down (0x25) - this prepares the pins for PRU0 output. The 'token_name:' is referenced in other fragments further down.
When initializing a device in the device tree, one must set the status to 'okay.' Then in order to do anything with that device, one must assign the pins created earlier:
fragment@2 {
target = <&pruss>;
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&token_name>;
};
};
The pin names can be left as 'default.' Sometimes there are other names that can be added for state manipulation such as found in the source file: cape-boneblack-hdmi-00A0.dts: pinctrl-names = "default", "off"; which can be seen in action through shell:
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
default
# echo off > /sys/devices/ocp.*/hdmi.*/pinmux_state
# cat /sys/devices/ocp.*/hdmi.*/pinmux_state
off
# echo "test" > /sys/devices/ocp.*/hdmi.*/pinmux_state
-sh: echo: write error: No such device
The following is a list of devices that can be modified or used via device tree overlays:
| am33xx_pinmux | ocp - on chip peripherals |
| tscadc - analog digital converter | mac - media access control |
| eCAP0_in_PWM0_out | eCAP1_in_PWM1_out |
| eCAP2_in_PWM2_out | tps - transaction processing system |
| mcasp0 - multichannel audio serial port | mcasp1 |
| eMMC_RSTn | gpmc - general purpose memory controller |
| pruss - programmable real-time unit subsystem | pru |
| pru0 | pru1 |
| spi0 - serial peripheral interface | spi1 |
| uart1 - universal asynchronous receive transmit | uart2 |
| uart3 | uart4 |
| uart5 | uart6 |
| i2c0 - inter-integrated circuit | i2c1 |
| i2c2 | intc - interrupt controller |
| ehrpwm0 - enhanced high resolution pwm | ehrpwm0A |
| ehrpwm0B | ehrpwm1 |
| ehrpwm1A | ehrpwm1B |
| ehrpwm2 | ehrpwm2A |
| ehrpwm2B | epwmss0 |
| epwmss1 - enhanced pulse-width mod. subsystem | epwmss2 |
| ecap0 - enhanced capture | ecap1 |
| ecap2 | edma - enhanced direct memory access |
| lcd - liquid crystal display | lcdc - liquid crystal display controller |
| aes - advanced encryption standard | sham |
| usb_otg_hs | tps-bl |
| dcan0 | dcan1 |
| clkout2 | mmc1 - multimedia card |
| mmc2 | mmc3 |
| timer1 | timer2 |
| timer3 | timer4 |
| timer5 | timer6 |
| timer7 | wdt |
| gpio1 - general purpose input output | gpio2 |
| gpio3 | gpio4 |
| gpio0_0-31 | gpio1_0-31 |
| gpio2_031 | gpio3_0-31 |
| P8.1-P8.46 | P9.1-P9.46 |
| rtc | usb - universal serial bus |
| sgx | mdio |
| . | . |
To compile the source, run the following shell command:
dtc -O dtb -o $NAME-$VERSION.dtbo -b 0 -@ $NAME-$VERSION.dts
To apply the new overlay, copy the *.dtbo file to /lib/framework and run the command:
echo $NAME > /sys/devices/bone_capemgr.*/slots
Confirm that it has loaded:
cat /sys/devices/bone_capemgr.*/slots
And to remove it, use the slot number where it is found:
echo -$SLOT_NUM > /sys/devices/bone_capemgr.*/slots
Tuesday, April 15, 2014
Pestering Adware
Though I may be a Linux user, and although there are programs such as 'wine' for emulating Windows-based apps in Linux, there is still software out there that can only run in Windows - including various Autodesk, Adobe, and Corel products, and so I remain in a windows environment. And as every seasoned Windows user knows, no matter how good one's anti-malware, -spyware, -adware, or anti-virus software is, there is always the rare occasion where it cannot do the job alone.
www.superfish.com, api.jollywallet.com, istatic.datafastguru.info, these are some of the URLs that pestered me for months and none of the programs I had available could find them. Thanks to Chrome's Console (Right Click > Inspect Element > Console) and the step-by-step descriptions provided here, I identified the foreign object and successfully removed it from my machine - no uninstalls and no system wipes!
(The following is for advanced users - a more descriptive approach can be found in the link provided above)
STEP 1:
STEP 2:
STEP 3:
STEP 4:
BONUS:
Back Story:
When browsing the web, I ensure that I have the following Chrome extensions installed and running: HTTPSEverywhere, AdBlocker, ScriptSafe (or no-script), and Blacklist. ScriptSafe has been a wonderful extension that allows me to be selective in what runs under the hood and what doesn't - it's like disabling JavaScript but only for some websites - saving me the worry of malicious scripts installing bad subjects on my system. One of the only downsides to this is that most sites use third-party scripts to help their website function the way they intended it. Some of the most common third-party scripts is jquery.min.js, three.js, and node.js which are like JavaScript libraries that save a developer a lot of time programming and designing.
About month or two ago, when attempting to reestablish functionality to a certain site, I mistakenly enabled an unfamiliar script. It fit right in with the others... I later found my self with about 3 trojans and 12 other objects. Malwarebytes, SpyBot, and CCleaner did what they could, but my browser's settings where altered - a new homepage, a new tabpage. Most of this was resolved with a quick reset, nevertheless, I noticed ScriptSafe displayed traces of www.superfish.com, api.jollywallet.com, and istatic.datafastguru.info. A colleague pointed me to the Chrome Extensions; sure enough there was an unauthorized extension. Removing it solved the problem - for a time.
www.superfish.com, api.jollywallet.com, istatic.datafastguru.info, these are some of the URLs that pestered me for months and none of the programs I had available could find them. Thanks to Chrome's Console (Right Click > Inspect Element > Console) and the step-by-step descriptions provided here, I identified the foreign object and successfully removed it from my machine - no uninstalls and no system wipes!
(The following is for advanced users - a more descriptive approach can be found in the link provided above)
STEP 1:
- - In the Registry Editor, navigate to:
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Policies\Google\Chrome - - Delete 'ExtensionInstallForcelist' or delete all the data within.
STEP 2:
- - Go to chrome://extensions/ and check 'Developer mode'
- - Search for all extensions that contain the line "Installed by enterprise policy." Save their name and id
(In my case, there was only one extension with the following information, NAME: YTBBloCkeaRApp ID meajhoiolabnglbkdopdglmmphjckgfp) - - Go to chrome://policy/ and click 'Show value'
- - Next to the ID should be a path to the malicious content. Navigate to that folder destination and remove the respective content.
STEP 3:
- Go to %AppData%\Local\Google\Chrome\User Data\Default\Extensions
- Delete the folder with the given ID
STEP 4:
- Go to C:\Windows\System32\GroupPolicy
- Delete 'Machine' and 'User' folders (following this step, Chrome will notify that the unwanted extension has been uninstalled)
BONUS:
- Re-scan to ensure all suspecting evidence is removed.
Back Story:
When browsing the web, I ensure that I have the following Chrome extensions installed and running: HTTPSEverywhere, AdBlocker, ScriptSafe (or no-script), and Blacklist. ScriptSafe has been a wonderful extension that allows me to be selective in what runs under the hood and what doesn't - it's like disabling JavaScript but only for some websites - saving me the worry of malicious scripts installing bad subjects on my system. One of the only downsides to this is that most sites use third-party scripts to help their website function the way they intended it. Some of the most common third-party scripts is jquery.min.js, three.js, and node.js which are like JavaScript libraries that save a developer a lot of time programming and designing.
About month or two ago, when attempting to reestablish functionality to a certain site, I mistakenly enabled an unfamiliar script. It fit right in with the others... I later found my self with about 3 trojans and 12 other objects. Malwarebytes, SpyBot, and CCleaner did what they could, but my browser's settings where altered - a new homepage, a new tabpage. Most of this was resolved with a quick reset, nevertheless, I noticed ScriptSafe displayed traces of www.superfish.com, api.jollywallet.com, and istatic.datafastguru.info. A colleague pointed me to the Chrome Extensions; sure enough there was an unauthorized extension. Removing it solved the problem - for a time.
Friday, April 4, 2014
Explorer DVL Wiring
It is unfortunate how much time has past trying to make this device work, and kind of sad to realize how easy it was in the end, but after a few phone calls and several strait hours of effort, our team finally managed to pull data from our Explorer Doppler Velocity Log from RD Instruments:
The problem was the wiring from sensor to computer. The documentation also was a little vague - indeed, a pinout table can be found on page 12 of the manual, but there are no further details about what the pins actually do like an integrated circuits' manuals would. Here are the pins and their values:
- 1: RX+ Messages received by the DVL Unit it's self.
- 2: RX- (Differential pair - RS422)
- 3: TX+ Messages transmitted by the DVL Unit it's self.
- 4: TX- (Differential pair - RS422)
- 5: COMM 1_2 0 = Com 1 (DVL Unit); 1 = Com 2;
If additional sensors and other devices were to be integrated with this as a full system, these pins would be used. (Our team never had a need as all other sensors were driven with real-time units)
- 6: RX2+; 7: RX2- (Diff. Pair);
- 8: TX2+; 9: TX2- (Diff. Pair);
- 11: RX3+; 12: RX3- (Diff. Pair);
- 13: TX3+; 14: TX3- (Diff. Pair);
- 15: COMM 3_4: 0 = Com 3; 1 = Com 4;
- 16: RX4+; 17: RX4- (Diff. Pair);
- 18: TX4+; 19: TX4- (Diff. Pair);
In some cases, a vehicle may contain more than one DVL and one cannot ping at the same time another does, otherwise things would end up in complete chaos. So, if one wishes to use say 4 at the same time, they would need a way to synchronize the pings. This can be done with the following pins: (NOTE: the following values are out of speculation, nevertheless their function has been confirmed by the engineers at RDI)
- 21: TRIG_IN 0 = wait; 1 = ping;
- 23: TRIG_OUT 0 = busy; 1 = finished;
And the various other pins that are good to have:
- 33: CHAS_GRND This would attach to the vehicle chassis
- 34/35: VDC+ 12-24V 3A MAX
- 36/37: VDC- 0V 0A
Now for the solution to our original problem - how to wire the device to a computer - for that I drew up a valuable schematic:
DB37-1 is connected to DB9-3: RX goes to TX
DB37-3 is connected to DB9-2: TX goes to RX
DB37-5 is connected to DB9-5: COMM 1_2 goes to GND
(I want to note that I happened to mix up pins 1 and 3 causing me grief for several hours. I didn't catch this silly mistake until I used an Arduino Uno to intercept the serial messages. The Arduino was reading data on the TX line but what's funny is that the data it was reading, originally came from the computer and not the DVL, Oops. In the end I ended up with TX to TX and RX to RX - that surely is not going to work, switch 'em around!)
Next, for up-to-date systems, a simple RS232 to USB adapter can be used. RDI recommended us the EasySYNC ES-U-1001, though I've tried another brand and the result was still the same.
With BBTalk (or the Arduino COM port), one can send and receive messages to the DVL.
Project: Success!
Saturday, March 29, 2014
Programming the BeagleBone's PRU
The BeagleBone Black is already a very powerful device with Linux under it's belt, but one thing many may not know is that the BeagleBone can also be programmed as two Real-Time units also (like having two Arduinos) - at least I never knew until the day before writing this post. Every bone comes with two PRUs (Programmable Real-Time Units).
In my efforts to learn what this feature was all about and how I could implement it, I unfortunately didn't find very much help from Google. This may have just been because I was looking in the wrong places though, nevertheless I found my answer(s) and so desire to share them here with you on my blog.
Simply Tutorials:
https://github.com/TekuConcept/PRU_Demo
PRUs on the bone are programmed with a special form of assembly specific to the TI platforms.
Time (or patience) may not be in your favor but I promise you: once you learn how to program with assembly in general, your eyes will be opened to the power and even more possibilities of your own computers beyond that which Linux and C++ has to offer - and the endless possibilities will overflow comprehension! (With assembly on any processing computer, you are literally telling the processor how to do it's job, just like when you program an Arduino. Assembly is to binary executable as hex is to binary value)
I recommend learning Assembly with Intel i386 processors [NASM] first before discovering Assembly with TI PRUs, and what better place to start than with these well put together tutorials at www.tutorialspoint.com/assembly_programming. Don't worry, once you've completed all the lessons there, you'll be able to jump right on into PRU programming using these links (or this post) as your guide:
- processors.wiki.ti.com/index.php/PRU_Assembly_Instructions,
- processors.wiki.ti.com/index.php/PRU_Assembly_Reference_Guide
Take a look at some tutorials/examples:
- http://boxysean.com/blog/2012/08/12/first-steps-with-the-beaglebone-pru/
(for the example.c file in the above, change the header locations from 'pruss/*.h' to '/usr/include/*.h')
- http://github.com/beagleboard/am335x_pru_package/tree/master/pru_sw/example_apps
- http://mythopoeic.org/bbb-pru-minimal/
Don't forget to run 'modprobe uio_pruss' before executing any PRU code! To enable PRU, try typing the following in shell: 'echo BB-BONE-PRU-01 > /sys/devices/bone_capemgr.9/slots'
Set up BeagleBone Black:
Check to see if the packages already exist with these shell commands:
whereis modprobe # or modprobe -h
whereis pasm # or pasm -h
...both of which should return file locations (or help info). If they do, you're all ready to roll.
Otherwise enter the following (these are the commands I tested with Debian):
Assembly Comparison:
"Nearly all instructions (with exception of accessing memory external to PRU) are single-cycle execute (5 ns when running at 200 MHz)" If you know Verilog some of this may be familiar...
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NASM memory registers:
In my efforts to learn what this feature was all about and how I could implement it, I unfortunately didn't find very much help from Google. This may have just been because I was looking in the wrong places though, nevertheless I found my answer(s) and so desire to share them here with you on my blog.
Simply Tutorials:
https://github.com/TekuConcept/PRU_Demo
PRUs on the bone are programmed with a special form of assembly specific to the TI platforms.
Time (or patience) may not be in your favor but I promise you: once you learn how to program with assembly in general, your eyes will be opened to the power and even more possibilities of your own computers beyond that which Linux and C++ has to offer - and the endless possibilities will overflow comprehension! (With assembly on any processing computer, you are literally telling the processor how to do it's job, just like when you program an Arduino. Assembly is to binary executable as hex is to binary value)
I recommend learning Assembly with Intel i386 processors [NASM] first before discovering Assembly with TI PRUs, and what better place to start than with these well put together tutorials at www.tutorialspoint.com/assembly_programming. Don't worry, once you've completed all the lessons there, you'll be able to jump right on into PRU programming using these links (or this post) as your guide:
- processors.wiki.ti.com/index.php/PRU_Assembly_Instructions,
- processors.wiki.ti.com/index.php/PRU_Assembly_Reference_Guide
Take a look at some tutorials/examples:
- http://boxysean.com/blog/2012/08/12/first-steps-with-the-beaglebone-pru/
(for the example.c file in the above, change the header locations from 'pruss/*.h' to '/usr/include/*.h')
- http://github.com/beagleboard/am335x_pru_package/tree/master/pru_sw/example_apps
- http://mythopoeic.org/bbb-pru-minimal/
Don't forget to run 'modprobe uio_pruss' before executing any PRU code! To enable PRU, try typing the following in shell: 'echo BB-BONE-PRU-01 > /sys/devices/bone_capemgr.9/slots'
Set up BeagleBone Black:
Check to see if the packages already exist with these shell commands:
whereis modprobe # or modprobe -h
whereis pasm # or pasm -h
...both of which should return file locations (or help info). If they do, you're all ready to roll.
Otherwise enter the following (these are the commands I tested with Debian):
- git clone git://github.com/beagleboard/am335x_pru_package.git
(I had trouble cloning directly to the bone so I cloned to my desktop and then used SFTP to copy the files over) - cd am335x_pru_package/pru_sw/app_loader/interface
- make CROSS_COMPILE=""
- cd ../../utils/pasm_source
- chmod u+x linuxbuild
- ./linuxbuild
- cd ../../utils
- mv pasm pasm_2
- cd ../example_apps
- make CROSS_COMPILE=""
- ldconfig
- cd am335x_pru_package/pru_sw/utils
- cp pasm /usr/bin/pasm
Assembly Comparison:
"Nearly all instructions (with exception of accessing memory external to PRU) are single-cycle execute (5 ns when running at 200 MHz)" If you know Verilog some of this may be familiar...
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NASM memory registers:
- 32bit: EAX, EBX, ECX, EDX
- 16bit: AX, BX, CX, DX
- 8bit: AH, AL, BH, BL, CH, CL, DH, DL
PRU memory registers:
- 32bit: r0, r1, r2, r3 . . . r30, r31
- 16bit: r0.w0, r0.w1 . . . r31.w0
- 8bit: r0.b0, r0.b1, r0.b2 . . . r31.b0
- 1bit: r0.t0, r0.b0.t0, r0.w1.t8 . . . r31.t31.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NASM general:
- MOV [dst],[src]: dst=src;
- MOV BYTE/WORD/DWORD/QWORD/TBYTE [dst],[src]
- JMP [label]: goto label;
- CALL [proc]: goto proc -> return to call;
- RET: return;
PRU general:
- MOV/LDI [dst],[src]: dst=src;
- MVIB/MVIW/MVID [dst],[src];
- LBBO [dst],[adr],[off],[cnt]: 'Copy cnt bytes into dst from memory address adr+off; cnt!=0'
- SBBO [src],[adr],[off],[cnt]: 'Copy cnt bytes from src to memory address adr+off; cnt!=0'
- ZERO [src],[sz]: memcpy(src, 0, sz);
- JMP [label]: goto label;
- JAL [rtrn],[label]: goto label -> return to rtrn;
- CALL [proc]: goto proc -> return to call;
- RET: return;
- WBS [src][val]: while(!(src&(1<<val)));
- WBC [src][val]: while(src&(1<<val));
- HALT: 'pauses PRU until manually resumed'
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NASM arithmetic:
- INC [a]: a++;
- DEC [a]: a--;
- ADD [a],[b]: a+=b;
- SUB [a],[b]: a-=b;
- MUL [m]: a*=m;
- IMUL [-m]: a*=-m;
- DIV [d]: a/=d;
- IDIV [-d]: a/=-d;
PRU arithmetic:
- ADD [v],[a],[b]: v=a+b;
- SUB [v],[a],[b]: v=a-b;
- ADC [v],[a],[b]: v=a+b+1;
- SUC [v],[a],[b]: v=a+b+1;
- RSB [v],[a],[b]: v=b-a;
- RSC [v],[a],[b]: v=b-a-1;
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
NASM logic:
- AND [a],[b]: a&=b;
- OR [a],[b]: a|=b;
- XOR [a],[b]: a^=b;
- NOT [a],[b]: a=~b;
- TEST [a],[b]: v=g.e.l (great.equal.less)
JG [label]: jumps if greater than
JE [label]: jumps if equal to
JL [label]: jumps if less than
PRU logic:
- AND [v],[a],[b]: v=a&b;
- OR [v],[a],[b]: v=a|b;
- XOR [v],[a],[b]: v=a^b;
- NOT [v],[a] : v=~a;
- MIN [v],[a],[b]: v=a<b?a:b;
- MAX [v],[a],[b]: v=a>b?a:b;
- LSL [v],[a],[b]: v=a<<b;
- LSR [v],[a],[b]: v=a>>b;
- CLR [v],[a],[b]: v=a&~(1<<b);
- SET [v],[a],[b]: v=a|~(1<<b);
Tuesday, February 18, 2014
Full C++ Socket Server on Linux
There are many examples online as to how to construct one's own client / server socket connection in C++, but unfortunately they do kind of take for granted that you know your stuff. Here I will share my working source code which satisfied the questions I asked but could not find:
For this, I used Linux Mint 16 in VirtualBox with a Bridged Network Connection (my virtual machine had it's own IP address assigned by the local network router). Also used a C/C++ Eclipse IDE and the GCC Compiler, here is my server code: (the client side that tested this is in C# on the host OS, Windows 7)
#include <iostream> // time, ctime
#include <cstdlib> // exit
#include <cstdio> // snprintf
#include <unistd.h> // gethostname, write, close, sleep
#include <netdb.h> // socket, htonl, htons
#define MAXHOSTNAME 256
void* memset(void* b, int c, size_t len);
int main()
{
int listenfd = 0, connfd = 0, n;
struct sockaddr_in serv_addr;
const int BUFF = 32;
char ioBuff[BUFF];
// create socket and flush memory blocks
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(ioBuff, '0', sizeof(ioBuff));
// set socket properties
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
serv_addr.sin_port = htons(8080);
// Initialize and start the socket
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
while(1)
{
// receive incoming connection
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
do
{
// read data from client
n = read(connfd, ioBuff, BUFF);
ioBuff[BUFF-1] = (char)NULL; // terminate string
std::cout << n << ": " << ioBuff;
// write data to client
write(connfd, ioBuff, BUFF);
// continue to read and write until '-1' is received
}while((int8_t)ioBuff[0] != -1);
// close connection and repeat
close(connfd);
sleep(1);
}
}
void* memset(void* b, int c, size_t len) {
char* p = (char*)b;
for (size_t i = 0; i != len; ++i) {
p[i] = c;
}
return b;
}
For a full C++ server and client example, see this post on www.thegeekstuff.com.
Back Story
As part of the same project mentioned in my earlier post, GPIO, BeagleBone, and Bash, the next challenge was to communicate with the device over a network. The first choice that came to mind was the secure shell (SSH). I needed to communicate programmatically using my language of choice, C#.
I found SSH.NET and put something simple together. As excited as I may have been for a successful connection, I was now facing some serious LAG! (You know, the same lag everyone notices when playing Super Smash Bros. Brawl world wide?) It is time for alternatives!
C# doesn't exactly have many good SSH libraries out there for some odd reason. One of those weird outcomes of Microsoft. Nevertheless, all is not lost... I could still do this in C++ and then write a wrapper around that in C#. Success! Using libssh, a free open-source C++ library, I am sending SSH commands much more quickly.
(I need to use C# because I have a library written only in C# - no other language. Though I do now have the source code and could port it, this task would prove time consuming considering several hundred lines of code and then would need debugging and testing letter on - maybe better for a future project)
Just about finished here, several friends point out, using SSH for what I'm trying to accomplish is overkill! Since I am not sending commands through the global network but a local one, I should not need these layers of security. Instead, I should construct a simple socket connection. Benefits: I can get an even faster speed-boost, and I can write the socket client in C# while the socket server is all in C++!
With my trial run, as of today (Feb 18, 2014), I am very pleased with the results!
For this, I used Linux Mint 16 in VirtualBox with a Bridged Network Connection (my virtual machine had it's own IP address assigned by the local network router). Also used a C/C++ Eclipse IDE and the GCC Compiler, here is my server code: (the client side that tested this is in C# on the host OS, Windows 7)
#include <iostream> // time, ctime
#include <cstdlib> // exit
#include <cstdio> // snprintf
#include <unistd.h> // gethostname, write, close, sleep
#include <netdb.h> // socket, htonl, htons
#define MAXHOSTNAME 256
void* memset(void* b, int c, size_t len);
int main()
{
int listenfd = 0, connfd = 0, n;
struct sockaddr_in serv_addr;
const int BUFF = 32;
char ioBuff[BUFF];
// create socket and flush memory blocks
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(ioBuff, '0', sizeof(ioBuff));
// set socket properties
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 0.0.0.0
serv_addr.sin_port = htons(8080);
// Initialize and start the socket
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(listenfd, 10);
while(1)
{
// receive incoming connection
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
do
{
// read data from client
n = read(connfd, ioBuff, BUFF);
ioBuff[BUFF-1] = (char)NULL; // terminate string
std::cout << n << ": " << ioBuff;
// write data to client
write(connfd, ioBuff, BUFF);
// continue to read and write until '-1' is received
}while((int8_t)ioBuff[0] != -1);
// close connection and repeat
close(connfd);
sleep(1);
}
}
void* memset(void* b, int c, size_t len) {
char* p = (char*)b;
for (size_t i = 0; i != len; ++i) {
p[i] = c;
}
return b;
}
For a full C++ server and client example, see this post on www.thegeekstuff.com.
Back Story
As part of the same project mentioned in my earlier post, GPIO, BeagleBone, and Bash, the next challenge was to communicate with the device over a network. The first choice that came to mind was the secure shell (SSH). I needed to communicate programmatically using my language of choice, C#.
I found SSH.NET and put something simple together. As excited as I may have been for a successful connection, I was now facing some serious LAG! (You know, the same lag everyone notices when playing Super Smash Bros. Brawl world wide?) It is time for alternatives!
C# doesn't exactly have many good SSH libraries out there for some odd reason. One of those weird outcomes of Microsoft. Nevertheless, all is not lost... I could still do this in C++ and then write a wrapper around that in C#. Success! Using libssh, a free open-source C++ library, I am sending SSH commands much more quickly.
(I need to use C# because I have a library written only in C# - no other language. Though I do now have the source code and could port it, this task would prove time consuming considering several hundred lines of code and then would need debugging and testing letter on - maybe better for a future project)
Just about finished here, several friends point out, using SSH for what I'm trying to accomplish is overkill! Since I am not sending commands through the global network but a local one, I should not need these layers of security. Instead, I should construct a simple socket connection. Benefits: I can get an even faster speed-boost, and I can write the socket client in C# while the socket server is all in C++!
With my trial run, as of today (Feb 18, 2014), I am very pleased with the results!
Friday, February 14, 2014
GPIO, BeagleBone, and Bash
As the AUVSI competing team electrical engineer at Utah State University, I have been tasked with the effort to turn our skeletal structure into an ROV (Remotely Operated underwater Vehicle) or in other words, an RC Sub. Well, volunteered, as a chance to get my hands messy with a few new electrical component: BeagleBone Black, Wii Classic Controller, and a few 14" VideoRay Thrusters w/Castle Creations ESCs! (If ever you want good experience and to learn new things outside of school, team-up and enter one of several special annual AUVSI competitions!)
Aside from the small story above, here is the real stuff I'd like to share for the benefit of all developers out there...
The task: Make an RC submarine
User input: Wii Classic Controller
RC Feedback: VideoRay Thruster Control
User-RC Linking: Wireless/WiFi
GPIO Pins!
The main challenge I encountered here is sending commands to the beaglebone and getting a pinout reaction from it. Arduino has the 'Serial' libraries but I'm not sure for the beaglebone. (It has been a bit of a challenge to find what I want exactly through Google.) Perhaps there is something, but for now, I found another way: my favorite Linux feature! The Bash/Shell Terminal!
Since Linux is a big fan of files, one doesn't need to go and write drivers to read and write IO data. With that said, one can simply read from or write to a GPIO pin just as they would any other file!
By default, GPIO 'files' have not been created yet and therefore need to be.
This can be done as follows:
# this will create the file for GPIO_30
# (Pin 11 on the P9 header)
echo 30 > /sys/class/gpio/export
Here is a pinout diagram of the BeagleBone Black:
Now to set the bin as an input or an output pin:
echo out > /sys/class/gpio/gpio30/direction # for output
echo in > /sys/class/gpio/gpio30/direction # for input
# NOTE: you can also set the pin to output
# and high or low at the same time by using
# 'high' or 'low' in place of 'out.'
To write to a pin, type the following shell command:
echo 1 > /sys/class/gpio/gpio30/value
# this will set GPIO_30 to high; 0 is for low
To read from a pin, type the following:
cat /sys/class/gpio/gpio30/value
# this will echo the current bit value of the wire
PWM Pins!
I spent a bit of time messing around with general purpose IO pins controlling my BBB with a Wiimote. Again, the overall objective is to control an AUV with the wiimote extensions. (Check out my socket server source code here. Simply use the system("") and a switch to run commands. For the wiimote part, I used a revised version of the wiimotelib library online as well as the C# client socket example from MSDN)
To get started with PWM output, we need to set up the environment:
echo am33xx_pwm > /sys/devices/bone_capemgr.9/slots
Next, to assign a pin: (these lines will assign pins P8_13 and P9_14 respectively)
echo bone_pwm_P8_13 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_14 > /sys/devices/bone_capemgr.9/slots
Set the period and duty for each pin:
# so 20000000 = 0.02 seconds
echo 20000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/period
# so 10000000 = 0.01 seconds
echo 10000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/duty
echo 20000000 > /sys/devices/ocp.3/pwm_test_P8_14.16/period
echo 10000000 > /sys/devices/ocp.3/pwm_test_P8_14.16/duty
And vuala, two pwm pins both running at 50%.
NOTE:
More Pins!
Sometimes what is available is still not enough! But, no worries; there is a way to acquire about an additional 20 pins - which include additional UARTs and PWMs. To do this, we must disable the auto-loading of the HDMI cape (assuming you will not need a display to work on):
cd /home/debian/Desktop
# cd /home/root/Desktop - for Angstrom distros
mkdir card
mount /dev/mmcblk0p1 card
nano card/uEnv.txt
# uncomment 'optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN'
# BE WARNED! If you disable the eMMC as well, you will never be able to access your bone again save it be through an SD card and would need to reinstall Linux otherwise. The eMMC is like your hard drive - you don't need it if and only if you boot from an SD card (like the blue steel bone)
# Save
umount card
rm -rf card
reboot
Happy exploring the Internet of Things!
Aside from the small story above, here is the real stuff I'd like to share for the benefit of all developers out there...
The task: Make an RC submarine
User input: Wii Classic Controller
RC Feedback: VideoRay Thruster Control
User-RC Linking: Wireless/WiFi
GPIO Pins!
The main challenge I encountered here is sending commands to the beaglebone and getting a pinout reaction from it. Arduino has the 'Serial' libraries but I'm not sure for the beaglebone. (It has been a bit of a challenge to find what I want exactly through Google.) Perhaps there is something, but for now, I found another way: my favorite Linux feature! The Bash/Shell Terminal!
Since Linux is a big fan of files, one doesn't need to go and write drivers to read and write IO data. With that said, one can simply read from or write to a GPIO pin just as they would any other file!
By default, GPIO 'files' have not been created yet and therefore need to be.
This can be done as follows:
# this will create the file for GPIO_30
# (Pin 11 on the P9 header)
echo 30 > /sys/class/gpio/export
Here is a pinout diagram of the BeagleBone Black:
Now to set the bin as an input or an output pin:
echo out > /sys/class/gpio/gpio30/direction # for output
echo in > /sys/class/gpio/gpio30/direction # for input
# NOTE: you can also set the pin to output
# and high or low at the same time by using
# 'high' or 'low' in place of 'out.'
To write to a pin, type the following shell command:
echo 1 > /sys/class/gpio/gpio30/value
# this will set GPIO_30 to high; 0 is for low
To read from a pin, type the following:
cat /sys/class/gpio/gpio30/value
# this will echo the current bit value of the wire
PWM Pins!
I spent a bit of time messing around with general purpose IO pins controlling my BBB with a Wiimote. Again, the overall objective is to control an AUV with the wiimote extensions. (Check out my socket server source code here. Simply use the system("") and a switch to run commands. For the wiimote part, I used a revised version of the wiimotelib library online as well as the C# client socket example from MSDN)
To get started with PWM output, we need to set up the environment:
echo am33xx_pwm > /sys/devices/bone_capemgr.9/slots
Next, to assign a pin: (these lines will assign pins P8_13 and P9_14 respectively)
echo bone_pwm_P8_13 > /sys/devices/bone_capemgr.9/slots
echo bone_pwm_P9_14 > /sys/devices/bone_capemgr.9/slots
Set the period and duty for each pin:
# so 20000000 = 0.02 seconds
echo 20000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/period
# so 10000000 = 0.01 seconds
echo 10000000 > /sys/devices/ocp.3/pwm_test_P8_13.15/duty
echo 20000000 > /sys/devices/ocp.3/pwm_test_P8_14.16/period
echo 10000000 > /sys/devices/ocp.3/pwm_test_P8_14.16/duty
And vuala, two pwm pins both running at 50%.
NOTE:
- As the duty cycle increases, an LED will dim, i.e. 10M is brighter than 15M.
- For my device, the path is /sys/devices/ocp.3/*, however another has reported their path to be located at /sys/devices/ocp.2/*. cd to /sys/devices and type 'ls' to list available titles.
More Pins!
Sometimes what is available is still not enough! But, no worries; there is a way to acquire about an additional 20 pins - which include additional UARTs and PWMs. To do this, we must disable the auto-loading of the HDMI cape (assuming you will not need a display to work on):
cd /home/debian/Desktop
# cd /home/root/Desktop - for Angstrom distros
mkdir card
mount /dev/mmcblk0p1 card
nano card/uEnv.txt
# uncomment 'optargs=quiet capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN'
# BE WARNED! If you disable the eMMC as well, you will never be able to access your bone again save it be through an SD card and would need to reinstall Linux otherwise. The eMMC is like your hard drive - you don't need it if and only if you boot from an SD card (like the blue steel bone)
# Save
umount card
rm -rf card
reboot
Happy exploring the Internet of Things!
Subscribe to:
Posts (Atom)

