Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


yyrkoon last won the day on December 10 2018

yyrkoon had the most liked content!

About yyrkoon

  • Rank
    Level 4
  • Birthday 07/05/1966

Profile Information

  • Gender
    Not Telling
  • Location

Recent Profile Visitors

4,739 profile views
  1. enl, I appreciate the sentiment. I'll tell you one thing. It's got me in the best shape I've been in years. Passed that,well it pays the bills. Not exactly the best job, but it allows me to live where I'm currently living. So not all bad. I get excited every whale season, go out with a few cameras, and come back with several awesome images of whales breaching,slapping tails, or whatever they're willing to share with us at the given time. Then, the local marine life is fairly outstanding as well. Last week, I took a road trip to the north shore( I live on the west side ) to a surf spot called Ho'okipa(Ho-Oh-Keep-A), and found myself taking pictures of children of all ages, and ethnic backgrounds. Surfing. Was very surprised to see a couple kids in the 5-6 years age range. Surfing by themselves ! Or at least standing on their boards on their own. It was pretty awesome. So yeah, the job I'm currently doing can definitely be grueling. In the end however, I think what I get to do, and see in my free time, is well worth it. Still, I'll be looking for that ever elusive remote job . . . EDIT: By the way, My facebook profile is William Hermans. Anyone wanting to check out the pictures I've taken in the last couple years is more than welcome. Images of everything from local flowers, or wildlife. To images of fish, in or out of the water, to Wahine(Women) surfers. The last being my favorite of course
  2. Hows everyone doing ? Just curious . . . So in the last two years, I have done zero coding. The contract for the last paid programming job I had ended in December 2017. When a buddy of mine( from High school ) found out and asked me if I wanted to visit / hangout at his place for a while. Since his place was/is located on Maui . . . yeah.Enough said. So again, no coding in the last couple years. Checking the local job offers through craigslist / news paper. Not many tech jobs become available here. However with the release of the Beaglebone AI, I started to get that itch again. Then within the last couple days, I finally saw a listing on craigslist that turned my head. C++ engineer job with preferred unreal(game engine) experience. The first person I thought of was Rick, when all of a sudden I realized it had been a while since I've visited here. Anyways, not really much going on here with me. Just working the typical job(Hospitality) making ends meet. Chasing after the local "wild life" What have you all been up to? Seriously considering taking a crash course in C++ / Unreal game engine. . .
  3. Everything still works fine with the latest version of code::blocks, and the first version of energia on Windows 10 x64 pro. In fact, the launchpad is recognized straight out of the box, without installing drivers. That is, at least for the purpose of flashing binaries to the launchpad. IN fact I've just flashed three TSSOP-20 parts, using the launchpad using a ZIP socket adapter + 20 pin TSSOP to DIP socket adapter.
  4. As do I appreciate anyone who tries to help me too. So, when I go to try something I've never done, I usually won't ask anyone for help per se. Usually I'll look for example code, and become familiar with how, and perhaps why it works. After that, because virtually no one writes code to my own "standards", I'll write something completely from scratch, as the shortest possible example I can think of. For myself to refresh my memory later on down the road if I ever need to. Because honestly, I do not retain hardware specific information in my head. Only some semblance Of the programming languages I use. But writing myself functioning, and concise example code, shows me exactly what I need to do, to achieve a certain goal, and then I know of several "mechanisms" (API's perhaps )to further that goal. Even if I have to look up a function prototype or two, to remember exactly how they work. Maybe I'm just one of those "odd ones out" ? EDIT: By the way when I say "virtually no one writes code to my standards . . ." I'm talking about style, and not ability.
  5. Simple Line / mux select So, this is a variation on using GPIO, via direct memory access. The benefit to using this code, or similar. Is that there is only two syscalls for each line / mux select. Versus 12 syscalls if using the standard "Linux way" using open(), write(), read(), and close(). That's PER pin. yikes. Keep in mind, I haven't put a ton of thought into this code, so it could very well be rough around the edges, but it does work. So for our particular application. We have a Line select for AIN6 on the beaglebone. As we needed more ADC channels. Again, for our own application, we needed 5 additional channels, with valid cmd line tool only accepting values 0-3, and 7. strtol() is set to base 16, so as not to interpret ASCII characters as the numerical value zero. Or potentially causing a seg fault. Put more correctly, if using base "10" as the numerical base value, values like 0x7, or absurdly large strings of characters could be interpreted as 0, and potentially something else undesirable. #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define GPIO0 (0x44E07000) #define GPIO2 (0x481AC000) #define GPIO_SIZE (0x2000) #define GPIO_DATAOUT (0x13C) #define GPIO_DATAIN (0x138) #define MA0 (1<<26) /*gpio_0*/ #define MA1 (1<<23) /*gpio_2*/ #define MA2 (1<<24) /*gpio_2*/ void line_select(uint8_t asp_value) { void *gpio_addr; unsigned int *bank0_out, *bank2_out; int fd = open("/dev/mem", O_RDWR); gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0); bank0_out = gpio_addr + GPIO_DATAOUT; gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO2); bank2_out = gpio_addr + GPIO_DATAOUT; close(fd); (asp_value & (1 << 0)) ? (*bank0_out |= MA0) : (*bank0_out &= ~(MA0)); (asp_value & (1 << 1)) ? (*bank2_out |= MA1) : (*bank2_out &= ~(MA1)); (asp_value & (1 << 2)) ? (*bank2_out |= MA2) : (*bank2_out &= ~(MA2)); printf("Line select: %u%u%u\n", !!(*bank2_out & MA2), !!(*bank2_out & MA1), !!(*bank0_out & MA0)); } int main(int argc, char *argv[]) { if(argc != 2) exit(1); int argv2 = strtol(argv[1], NULL, 16); if(argv2 != 7){ if(argv2 < 0 || argv2 > 3) exit(1); } line_select(argv2); return 0; } Output: root@wgd:~/dl-i2c-test# nano tst.c root@wgd:~/dl-i2c-test# gcc -Wall -o tst tst.c root@wgd:~/dl-i2c-test# ./tst 0 Line select: 000 root@wgd:~/dl-i2c-test# ./tst 1 Line select: 001 root@wgd:~/dl-i2c-test# ./tst 2 Line select: 010 root@wgd:~/dl-i2c-test# ./tst 3 Line select: 011 root@wgd:~/dl-i2c-test# ./tst 4 root@wgd:~/dl-i2c-test# ./tst 0x7 Line select: 111 root@wgd:~/dl-i2c-test# ./tst 0xFF root@wgd:~/dl-i2c-test# ./tst -1 root@wgd:~/dl-i2c-test#
  6. For those of you who are interested. I made it easy to find the pin info "spread sheet" info on a new git here: https://github.com/wphermans/bb-info
  7. Working with GPIO, closer to the hardware: In addition to the "traditional Linux" way of working through the file system when using hardware. One can use mmap() and /dev/mem/, when absolute performance is needed, or perhaps if one needs to minimize the load put on the processor when dealing with GPIO hardware. One does need to be aware that when doing so, all operations on the hardware used is done without the kernel knowing. This is kind of a misnomer, as Linux will "eventually" know something is happening, and adjust the sysfs entries accordingly. *Assuming*, Linux even knows such hardware even exists by way of loading the appropriate drivers. Which does not have to be the case. One can essentially write their own "driver" from userspace using this technique. But you may have to set the hardware up manually through it's respective registers. I'll leave further explanation up as an exercise to the reader to figure out. As I do not fully understand the implications, for each hardware module on the AM335x processor myself. GPIO, is easy, but something such as PWM, ADC, or I2C, etc requires more than a simple configuration to get working properly. Anyway, some of this code will probably need further explanation, so I will pick apart some of the code and explain what is happening after the fact. Code: #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <sys/mman.h> #include <sys/types.h> #include <sys/stat.h> #include <errno.h> #include <fcntl.h> #define GPIO0 (0x44E07000) #define GPIO1 (0x4804C000) #define GPIO2 (0x481AC000) #define GPIO3 (0x481AE000) #define GPIO_SIZE (0x2000) #define GPIO_DATAOUT (0x13C) #define GPIO_DATAIN (0x138) #define PWM1 (1<<2) /*gpio_0*/ #define PWM2 (1<<3) /*gpio_0*/ #define PWM3 (1<<18) /*gpio_1*/ #define PWM4 (1<<22) /*gpio_0*/ #define PWM5 (1<<19) /*gpio_1*/ #define PWM6 (1<<23) /*gpio_0*/ #define Z1IN (1<<12) /*gpio_1*/ #define Z2IN (1<<13) /*gpio_1*/ #define Z3IN (1<<14) /*gpio_1*/ #define Z4IN (1<<15) /*gpio_1*/ #define Z5IN (1<<16) /*gpio_1*/ #define Z6IN (1<<17) /*gpio_1*/ int main(int argc, char *argv[]) { void *gpio_addr; unsigned int *gpio0_out; unsigned int *gpio1_out, *gpio1_in; int fd = open("/dev/mem", O_RDWR); gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO0); gpio0_out = gpio_addr + GPIO_DATAOUT; gpio_addr = mmap(0, GPIO_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, GPIO1); gpio1_out = gpio_addr + GPIO_DATAOUT; gpio1_in = gpio_addr + GPIO_DATAIN; close(fd); *gpio0_out |= PWM1 + PWM2 + PWM4 + PWM6; *gpio1_out |= PWM3 + PWM5; usleep(1000); printf("PWM1 %u Z1IN %u\n", !!(*gpio0_out & PWM1), !!(*gpio1_in & Z1IN)); printf("PWM2 %u Z2IN %u\n", !!(*gpio0_out & PWM2), !!(*gpio1_in & Z2IN)); printf("PWM3 %u Z3IN %u\n", !!(*gpio1_out & PWM3), !!(*gpio1_in & Z3IN)); printf("PWM4 %u Z4IN %u\n", !!(*gpio0_out & PWM4), !!(*gpio1_in & Z4IN)); printf("PWM5 %u Z5IN %u\n", !!(*gpio1_out & PWM5), !!(*gpio1_in & Z5IN)); printf("PWM6 %u Z6IN %u\n", !!(*gpio0_out & PWM6), !!(*gpio1_in & Z6IN)); printf("\n"); *gpio0_out &= ~(PWM1 + PWM2 + PWM4 + PWM6); *gpio1_out &= ~(PWM3 + PWM5); usleep(1000); printf("PWM1 %u Z1IN %u\n", !!(*gpio0_out & PWM1), !!(*gpio1_in & Z1IN)); printf("PWM2 %u Z2IN %u\n", !!(*gpio0_out & PWM2), !!(*gpio1_in & Z2IN)); printf("PWM3 %u Z3IN %u\n", !!(*gpio1_out & PWM3), !!(*gpio1_in & Z3IN)); printf("PWM4 %u Z4IN %u\n", !!(*gpio0_out & PWM4), !!(*gpio1_in & Z4IN)); printf("PWM5 %u Z5IN %u\n", !!(*gpio1_out & PWM5), !!(*gpio1_in & Z5IN)); printf("PWM6 %u Z6IN %u\n", !!(*gpio0_out & PWM6), !!(*gpio1_in & Z6IN)); return 0; } Output: root@wgd:~/dl-i2c-test# gcc -Wall -o tst tst.c root@wgd:~/dl-i2c-test# ./tst PWM1 1 Z1IN 0 PWM2 1 Z2IN 0 PWM3 1 Z3IN 0 PWM4 1 Z4IN 0 PWM5 1 Z5IN 0 PWM6 1 Z6IN 0 PWM1 0 Z1IN 1 PWM2 0 Z2IN 1 PWM3 0 Z3IN 1 PWM4 0 Z4IN 1 PWM5 0 Z5IN 1 PWM6 0 Z6IN 1 So the first thing to understand about this code is that it will return the output immediately after the command is issued. Partly this has to do with using sleep() in the first example, and usleep() in this example. 1 Second sleep, versus a 1000 uSec( 1 millisecond ) sleep. I will say however, that the timing cut off for reading from a GPI with the current kernel I'm using ( which is RT PREEMPT by the way ) is between 500 uSec, and 1000 uSec. Exactly where, I'm not sure, but I've tested all the way down to 10 uSec, and the slew rate of the GPI's at this speed are far too slow. e.g. I get back incorrect readings, even though visual inspection( LEDs ) shows everything working correctly. Now it may be possible to speed up the sysfs method by using usleep() instead, but be aware there would be ~5 syscalls per pin group, and these calls would hinder performance greatly when compared to this method. Now a bit of code explanation: #define GPIO0 (0x44E07000) #define GPIO1 (0x4804C000) #define GPIO2 (0x481AC000) #define GPIO3 (0x481AE000) The base address for each GPIO bank. So how do "We" know these addresses ? Well, you can read the TRM for the AM355x processor, and get this information. But there is an easier way. root@wgd:~/dl-i2c-test# ls /sys/devices/platform/ocp/*.gpio/gpio/ /sys/devices/platform/ocp/44e07000.gpio/gpio/: gpio2 gpio22 gpio23 gpio26 gpio3 gpiochip0 /sys/devices/platform/ocp/4804c000.gpio/gpio/: gpio44 gpio45 gpio46 gpio47 gpio48 gpio49 gpio50 gpio51 gpio60 gpiochip32 /sys/devices/platform/ocp/481ac000.gpio/gpio/: gpio86 gpio87 gpio88 gpiochip64 /sys/devices/platform/ocp/481ae000.gpio/gpio/: gpio110 gpio111 gpio112 gpio115 gpio117 gpiochip96 Now, not only this easier to figure out the base addresses for each GPIO bank. But if like me you do not memorize each gpioxx number, this will tell you which GPIO bank each pin is on. When using a device tree overlay file to configure your pins. Very handy. As glancing at this is much easier than parsing a spread sheet when you're doing this: #define PWM1 (1<<2) /*gpio_0*/ #define PWM2 (1<<3) /*gpio_0*/ #define PWM3 (1<<18) /*gpio_1*/ #define PWM4 (1<<22) /*gpio_0*/ #define PWM5 (1<<19) /*gpio_1*/ #define PWM6 (1<<23) /*gpio_0*/ #define Z1IN (1<<12) /*gpio_1*/ #define Z2IN (1<<13) /*gpio_1*/ #define Z3IN (1<<14) /*gpio_1*/ #define Z4IN (1<<15) /*gpio_1*/ #define Z5IN (1<<16) /*gpio_1*/ #define Z6IN (1<<17) /*gpio_1*/ These numbers: #define GPIO_SIZE (0x2000) #define GPIO_DATAOUT (0x13C) #define GPIO_DATAIN (0x138) You will have to read the TRM, to figure out, if you need to be absolutely certain. However know that the page_file size in Linux will always be a multiple of 4k, and I just so happen to know off the top of my head that each GPIO bank "width" is 8192 bytes. To store all the GPIO configuration registers. Or PAGE_FILE_SIZE * 2. Now onto something that many people may not know. printf("PWM1 %u Z1IN %u\n", !!(*gpio0_out & PWM1), !!(*gpio1_in & Z1IN)); !! in this case is not one, but actually two operators. Basically NOT NOT, which essentially works as a shorthand for a ternary conditional check. Returning a value of 0, or 1. Kind of a hack, that is definitely not self explanatory at first glace.Until you work it out in your head what is actually going on. Then, it's something that becomes obvious. I'd argue that this short hand form is actually as readable as a "proper" ternary conditional check.
  8. Working with GPIO: So where to start. GPIO is probably one of the most easiest things to work with on a beaglebone. Once you understand a few things. First, the kernel through sysfs has no idea what pins are tied to which header pin. So one needs to find a spread sheet that will explain which header pin is attached to which GPIO pin through the sysfs file structure. The base path for the sysfs gpio path is /sys.class/gpio/. However the explanation of how all this works is fairly lengthy, and there are a lot of guides dating back to the original bealgebone(white) as to how all this works. In short, if you need to know this information I suggest you search the web for information. This is the "manual" way of setting up GPIO. Another alternative is again to use a device tree overlay file. Which in of it's self is initially a lengthy process to understand. In short: https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/univ-nhdmi-00A0.dts#L232-#L234 The highlighted text here is defining a pin number, and the mode that pin needs to be set into for GPIO operation, with pullup, and RxActive enabled. These files for the purpose of this explanation are not exactly the best to use. Perhaps at some point in the future Ill create a simple overlay file, for the purpose of better explanation. As it is, this particular overlay is for Universal IO, and it covers most, if not all pins, with most if not all possible modes for each pin. Used with config-pin this allows one to configure each pin as needed dynamically from the command line . . . So onto some simple code. First, again, some explanation is required. For our board we have some PWM pins, and some input pins, among other things. Both PWM, and input only use 6 pins each. In order to test the circuitry of our boards, To test the our capes circuitry, we instead use the PWM pins as GPO's, the input pins as GPI's, and have a test header connecting each "zone" together from GPO to GPI. Additionally, there is an LED connected to each GPO on this test header for visual inspection. Code: #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> #define HIGH 1 #define LOW 0 #define PWM1 2 #define PWM2 3 #define PWM3 50 #define PWM4 22 #define PWM5 51 #define PWM6 23 #define Z1IN 44 #define Z2IN 45 #define Z3IN 46 #define Z4IN 47 #define Z5IN 48 #define Z6IN 49 void set_pin(int pin_num, int value) { char gpio_path[40] = {0}; char str_value[2] = {0}; sprintf(str_value, "%d", value); sprintf(gpio_path, "/sys/class/gpio/gpio%d/value", pin_num); int fd = open(gpio_path, O_WRONLY); if(fd == -1){ perror(gpio_path); exit(1); } int nread = write(fd, str_value, 1); if( nread < 0){ perror("write()"); exit(1); } close(fd); } int get_pin(int pin_num) { char gpio_path[40] = {0}; char str_value[2] = {0}; sprintf(gpio_path, "/sys/class/gpio/gpio%d/value", pin_num); int fd = open(gpio_path, O_RDONLY); if(fd == -1){ perror(gpio_path); exit(1); } read(fd, str_value, sizeof(str_value - 1)); close(fd); return strtol(str_value, NULL, 10); } int main() { set_pin(PWM1, LOW); set_pin(PWM2, LOW); set_pin(PWM3, LOW); set_pin(PWM4, LOW); set_pin(PWM5, LOW); set_pin(PWM6, LOW); sleep(1); printf("PWM1: %i Z1IN: %i \n", get_pin(PWM1), get_pin(Z1IN)); printf("PWM2: %i Z2IN: %i \n", get_pin(PWM2), get_pin(Z2IN)); printf("PWM3: %i Z3IN: %i \n", get_pin(PWM3), get_pin(Z3IN)); printf("PWM4: %i Z4IN: %i \n", get_pin(PWM4), get_pin(Z4IN)); printf("PWM5: %i Z5IN: %i \n", get_pin(PWM5), get_pin(Z5IN)); printf("PWM6: %i Z6IN: %i \n", get_pin(PWM6), get_pin(Z6IN)); printf("\n"); /***********************************************************/ set_pin(PWM1, HIGH); set_pin(PWM2, HIGH); set_pin(PWM3, HIGH); set_pin(PWM4, HIGH); set_pin(PWM5, HIGH); set_pin(PWM6, HIGH); sleep(1); printf("PWM1: %i Z1IN: %i \n", get_pin(PWM1), get_pin(Z1IN)); printf("PWM2: %i Z2IN: %i \n", get_pin(PWM2), get_pin(Z2IN)); printf("PWM3: %i Z3IN: %i \n", get_pin(PWM3), get_pin(Z3IN)); printf("PWM4: %i Z4IN: %i \n", get_pin(PWM4), get_pin(Z4IN)); printf("PWM5: %i Z5IN: %i \n", get_pin(PWM5), get_pin(Z5IN)); printf("PWM6: %i Z6IN: %i \n", get_pin(PWM6), get_pin(Z6IN)); return 0; } Output: root@wgd:~/dl-i2c-test# gcc -Wall -o read_zonein read_zonein.c root@wgd:~/dl-i2c-test# ./read_zonein PWM1: 0 Z1IN: 1 PWM2: 0 Z2IN: 1 PWM3: 0 Z3IN: 1 PWM4: 0 Z4IN: 1 PWM5: 0 Z5IN: 1 PWM6: 0 Z6IN: 1 PWM1: 1 Z1IN: 0 PWM2: 1 Z2IN: 0 PWM3: 1 Z3IN: 0 PWM4: 1 Z4IN: 0 PWM5: 1 Z5IN: 0 PWM6: 1 Z6IN: 0 As one can see the logic between inputs, and output is reversed. This is of course intentional.
  9. I added a couple pictures here: https://plus.google.com/u/0/106867156582775247949 with a short explanation of each. It's much easier for me to just make post on my google+ page and then link back here. I am intentionally going slow with my project here. I want to make sure it all works out good. As it is, I will need to trim the aliminum tray part I ordered precut, to the mini ITX motherboard standard. After that, I'll also have to take measurements of the board, and mark mounting holes. Also from the mini ITX motherboard standard. EDIT: For those of you who also may be interested in the mini ITX specification: http://www.formfactors.org/developer/specs/mini_itx_spec_v1_1.pdf The PDF also covers the mATX, and ATX standards if I'm not mistaken.
  10. How to read an ADC So this bit may seem a little odd to some. Hell I know the hardware, and wrote this really quick snippet as a demonstration, and I think it's odd. The short story here. Is that we have a pin multiplexer on AIN6, and this multiplexer selects an external channel based on a bit pattern sent to it through 3 GPIO pins. That code I won't be showing in this post. but I wanted to point out why I have an odd "mvolts" value. Which indicates maximum input voltage before the voltage limiting resistor network. e.g. the on board ADC pins can only handle 1.8v absolute maximum voltage, and I'm pretty sure without all circuitry voltage drop, outside maximum voltage is supposed to be 0-10v, and wulf probably designed the voltage into the ADC it's self to be less than 1.5v . . . So I started with 10v in mind, saw the reading was definitely too high, and then played a guessing game until the voltage I read from a volt meter, matched what I was reading through the ADC. So there is definite resolution loss here . . . Anyway, the best and easiest way to load drivers for the ADC is to load the stock ADC overlay from /lib/firmware/. root@wgd:~# ls /lib/firmware/ |grep ADC BB-ADC-00A0.dtbo That is the file to load. Which can be loaded through capemgr via the command line manually, or from /boot/uEnv.txt at boot. ADC C code: #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdio.h> #include <errno.h> #include <stdlib.h> const char *ain6 = "/sys/bus/iio/devices/iio:device0/in_voltage6_raw"; int main() { int fd; int len; char adc[5] = {0}; float madc = 4095.0f; float mvolts = 7.7f; float bvolts = (mvolts / madc); fd = open(ain6, O_RDONLY); if(fd == -1){ perror("ain6"); exit(1); } len = read(fd, adc, sizeof(adc - 1)); int adc_val = strtol(adc, NULL, 10); float voltage = adc_val * bvolts; printf("%f \n", voltage); close(fd); return 0; } Output: root@wgd:~# gcc -Wall -o adc adc.c adc.c: In function 'main': adc.c:14:6: warning: variable 'len' set but not used [-Wunused-but-set-variable] int len; ^ root@wgd:~# ./adc 0.030085 A couple things to notice here. First is the warning I'm getting back from the compiler. This is because I'm using the -Wall option, which pretty much tells the compiler to use strict reporting of warnings. It is my belief that one should always at least use the -Wall compiler flag. Then we should treat these warning as if they're errors, and correct them. Which( and yeah I hate explanations like this too ) I'm ignoring for this one situation. Basically "len" is a return value from read() which can let us know how many bytes were read out of the file, and we absolutely should test this value for a non negative number. Then act on negative numbers as an error, which could be done a few different ways. For this demo, I was not sure in a pinch what would be a better way to handle that potential error. Mostly because I know these values will always be 0-4095, unless there is a problem with the hardware. At which point we're done anyhow( probably a blown processor ). One way to deal with this kind of error, would be to use perror() followed by exit(errno) in an if block. But at this point I'm fairly confident the system would not be running anyway . . .However, the values coming out of the ADC module should always be 1-4 characters, so how do we test for no characters ? NULL, but if we're reading out a NULL, how did our code make it thus far anyhow ? Additionally, if we're reading more than 4 character . . .Not only do I believe this to be impossible because of the way I wrote this code, but if it were somehow possible. We'd have a buffer overrun. Which may be a very good idea to test for. If for nothing else, good practice ? You decide. Secondly, the really low, but not absolute zero value. Well, I've come to realize that when working with circuits of this nature, that can not tied to ground, or pulled high. You're basically "floating" but close to a low, or a high . . . again, I'm not exactly an EE, so maybe someone who cares to can elaborate further. But I always think of this sort of situation as induced parasitic voltages from the circuitry. I'm definitely all ears if someone has a better explanation, or insight into this. . .But I've tested these readings against a volt meter, and am reasonably happy that I'm "close enough" for my own purposes. Someday, perhaps I'll buy a USB computer style Oscilloscope, in hopes to enlighten myself further..
  11. Read from a DS18B20 temperature sensor Again, very simple code to read from a device, and put that read information out to stdout. In this case, reading from a 1-wire DS18B20 sensor. The pin used is unimportant, so long as that pin is configurable as gpio, and is not already in use by another device. 1-wire is one of the simpler sensors to connect to a beaglebone, and can be plugged directly into one of the two headers on the beaglebone using jumper wires. You need power(3v3), ground, and a gpio pin connected. See the DS18B20 datasheet to determine which pin on the sensor is used for what purpose. As for setup in Linux for this sensor. You can search the web for a guide as to how to do this manually from the cmdline, or you can use a device tree overlay. I used this overlay file as a template, then modified the pin information to reflect the pin I needed to use. https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/BB-W1-P9.12-00A0.dts C code: #include <stdio.h> #include <dirent.h> #include <string.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> int read_DS18B20(void) { DIR *dir; struct dirent *dirent; char dev[16]; char devPath[128]; char buf[80]; char tmpData[6]; char path[] = "/sys/bus/w1/devices"; ssize_t nread; dir = opendir(path); if(dir == NULL){ perror("/sys/bus/w1/devices"); exit(errno); } while((dirent = readdir(dir))){ if (dirent->d_type == DT_LNK && strstr(dirent->d_name, "28-") != NULL){ strcpy(dev, dirent->d_name); } } (void)closedir(dir); sprintf(devPath, "%s/%s/w1_slave", path, dev); int fd = open(devPath, O_RDONLY); if (fd == -1){ perror ("/sys/bus/w1/devices/28-*/w1_slave"); exit(errno); } long tempC = 0; nread = read(fd, buf, 80); if(nread > 0){ strncpy(tmpData, strstr(buf, "t=") + 2, 5); tempC = strtol(tmpData, NULL, 10); } close(fd); return tempC; } int main (void) { float temp = read_DS18B20() * (1 / 1000.0); printf("Temp: %.3f C \n", temp); return 0; } Output: root@wgd:~/# gcc -Wall -o read_ds18b20 read_ds18b20.c root@wgd:~/# ./read_ds18b20 Temp: 25.312 C
  12. So, this is partly for me, and partly for others who need a refresher, or just do not know how. But I will be making several post here over time on how to write very simply code, to do one thing, or another. These, used in conjunction with a shell script could be very useful / flexible. After several long talks with many people, including some here on these very forums. I've decided that using C, to communicate with hardware, or hardware interfaces is best as can be for many situations. However, when you need to run several tools all at once, and have output formatted in some fashion, or easily modified. Shell scripts are very good at that sort of thing. Read from a real-time clock This post I will make about reading from a real-time clock. I spent hours messing around code related to I2C communications, and could never get exactly what I wanted. Plus, I wanted something that output date / time that looked very similar to the date Linux command. This could definitely been done using a shell script, but code size would probably be a lot larger. Additionally, a shell script would very likely be a lot slower, as with a script, one would have to be calling external cmdline tools to perform various operations. This example code is very fast, and prints to screen immediately after issuing the command. Since this command is very simple, and only prints the formatted date / time to screen. This could very easily be called from a shell script, and formatted further if need be. The real-time clock I'm using for this demonstration is a Maxim DS3232 real-time clock which is very accurate, and also very expensive compared to other real-time clocks. At $7 + US each, it's not cheap. I also had to write my own device tree overlay for this RTC, which strictly speaking is not necessary. One can set the device up from the command line manually as demonstrated for many different RTC's on the web. In fact, all the device tree overlay that I wrote does, is set all this automatically up at boot. As far as teh actual overlay it's self. All I did was modify an existing overlay from the "official" bb-overlays repo on github. https://github.com/beagleboard/bb.org-overlays/blob/master/src/arm/BB-RTC-01-00A0.dts To look something like this: /* * Copyright (C) 2015 Robert Nelson <robertcnelson@gmail.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */ /dts-v1/; /plugin/; #include <dt-bindings/board/am335x-bbw-bbb-base.h> #include <dt-bindings/gpio/gpio.h> #include <dt-bindings/pinctrl/am33xx.h> / { compatible = "ti,beaglebone", "ti,beaglebone-black", "ti,beaglebone-green"; /* identification */ part-number = "BB-RTC-01"; version = "00A0"; fragment@2 { target = <&i2c2>; __overlay__ { status = "okay"; /* shut up DTC warnings */ #address-cells = <1>; #size-cells = <0>; /* MCP79410 RTC module */ rtc@68 { compatible = "maxim,ds3232"; reg = <0x68>; }; }; }; }; On our cape, the RTC is on bus I2C-2, which is already enabled by default for capemgr. The rest of the above just means that status is okay(load the device ), the kernel module to load is called "ds3232", and the device address on the bus is 0x68. Now on to the actual C code for reading from /dev/rtc1: #include <stdio.h> #include <stdlib.h> #include <linux/rtc.h> #include <sys/ioctl.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <unistd.h> #include <errno.h> void display_date_time(void) { struct rtc_time rtc_tm; int fd = open("/dev/rtc1", O_RDONLY); if(fd == -1){ perror("/dev/rtc"); exit(errno); } /* Read the RTC time/date */ int retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); if (retval == -1) { perror("ioctl"); exit(errno); } int d = rtc_tm.tm_mday; int m = rtc_tm.tm_mon + 1; int y = rtc_tm.tm_year + 1900; const char *wdays[] = {"Sun","Mon","Tues","Wed","Thur","Fri","Sat"}; const char *mnths[] = {"Jan","Feb","Mar","Apr","May","June","July","Aug","Sept","Oct","Nov","Dec"}; int wday = (d += m < 3 ? y-- : y - 2, 23*m/9 + d + 4 + y/4- y/100 + y/400)%7; fprintf(stdout, "%s %s %02d %02d:%02d:%02d %d UTC\n", wdays[wday], mnths[rtc_tm.tm_mon], rtc_tm.tm_mday, rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec, y); } int main( int argc, char **argv ) { display_date_time(); return 0; } As one can see, most of this code is for formatting the output in a specific way. In this case, the output will look exactly like the output one might expect to see after issuing the command "date". However, this output is fixed to output the date / time in the UTC time zone. As for one of the projects I'm using this in is for devices spread out all over the US, in 3 different time zones, and we do not care so much what the local time zone of that system so much, as much as knowing a given time "standard". e.g. if something fails, and we need to tell a customer what failed, and what time it failed, we can, Then if we need to convert that time to their time zone, easy. Notice that the read() is handled by ioctl(). . . Output: root@wgd:~/# gcc -Wall -o read_rtc read_rtc.c root@wgd:~/# ./read_rtc Tues May 09 23:08:49 2017 UTC
  13. So, almost everything I need is here. There only thing I'm missing is the non conductive M3 standoff washer( dont know what else to call them ), and the actual 1/4" screws that screw into the standoffs. Just playing around today, I took the main board tray piece of aluminum I have precut, and marked out the screw holes to mount it to the case frame. How I did this was cut a piece of cardboard exactly the same size as the piece of aluminum I had cut, put it into the case, pressed down on the cardboard until I got indentations form the mounting standoffs. Then I drill out the center of these indentations, and scribed onto aluminum with a fine point sharpie. I was not very happy with this result. So something I was thinking about the other day, and wulf reminded me of today, was to go find the standard for mini itx boards, and get the measurments from that. Gee, why didn't I think of that, which I did, just forgot . . .but i did find this: http://www.formfactors.org/developer/specs/mini_itx_spec_v1_1.pdf Perfect, so all I need now is daylight, and a bit of time. Then I'll revisit / re-approach this problem and get busy. I did take a few pictures, but they're still on the phone, and I CBF'd right now to upload them Perhaps later.
  14. Yeah after watching this video on gitlab: https://www.youtube.com/watch?v=PoBaY_rqeKA I've concluded for now, it's a bit more complex than I want. Granted . . . git it's self is fairly complex too, but gitlab would be something else I had to read up on, and keep up with, when all I really want is to feel all warm and fuzzy about my data being there when I need it. I may even think about making my backup strategy even simplier than what I'm currently think it should be now. May even forgo git all together, and just use rsync in conjunction with dd or tar. For 3 layers of redundancy. But I do liek the idea of versioning . . . a lot.
  15. It sounds interesting. Having a web based GUI could be useful, if that's what it is. Quite honestly though, and do keep in mind im by far not a git guru. I prefer to use tools of this nature form the command line. Honestly, I find using the tools much quicker from the command line. and this way keeps me in touch with how the tool is used. So if someday I wish to script something up, it should be trivial. Which is something else I've been doing a lot of. Which also lends a lot to readability for anyone who knows their way around a Linux system. So when working with others, like for me at work, I designed a complete monitoring system for production boards that anyone at work can read, and understand fairly quickly Even the boss, who is actually an old school embedded *NIX systems software developer. Anyway, for me, I'm not doing a local backup through git right now. But I have invested a considerable amount of time reading about it over the last year or so. So it's just a matter of time before I follow through. Then like I mentioned in a previous post. I'll have a completely separate partition, and mostly like a completely separate disk that I mount only when making backups. and probably using something like dd, to make 1:1 copies, or perhaps just using tar. So mount -> backup -> umount. This for me, will be very robust, and about as bullet proof as I would care to get. However, the system doing backups, for me would require a UPS, and possibly may just be a laptop for the built in battery power in case of power failures. Which is partly why I have not followed through with this yet. I want everythign runable during a power failure, and I have not had any of the required circutry, and possibly code designed yet. A friend of mine however( not wulf ) have been talking seriously about a design for a while now. Something he'll design in hardware, and something I'll design in software, assuming software will ever be needed.
  • Create New...