How to get images from raster bands using OpenCV? - opencv

I have different raster bands and I need to get a proper image from these bands using OpenCV. How can it be done?

As an alternative to my other answer, you could put a small ASCII header on your raw files to make them into PGM files which OpenCV can read natively without any extra libraries. The PGM format is part of the NetPBM suite described here on Wikipedia.
So, let's say each of your rasters is a single channel, 8-bit image with dimensions 100 px wide by 256 px tall. Make each band into a PGM image in the Terminal:
{ printf "P5\n100 256\n255\n"; cat band1.dat; } > band1.pgm
{ printf "P5\n100 256\n255\n"; cat band2.dat; } > band2.pgm
{ printf "P5\n100 256\n255\n"; cat band3.dat; } > band3.pgm
{ printf "P5\n100 256\n255\n"; cat band4.dat; } > band4.pgm
You now have 4 greyscale images you can view with GIMP or feh and, more importantly which OpenCV can read. So your code becomes:
Mat b1 = imread("band1.pgm", IMREAD_UNCHANGED);
Mat b2 = imread("band2.pgm", IMREAD_UNCHANGED);
Mat b3 = imread("band3.pgm", IMREAD_UNCHANGED);
Mat b4 = imread("band4.pgm", IMREAD_UNCHANGED);
// Now merge
auto channels = std::vector<cv::Mat>{b1, b2, b3, b4};
cv::Mat FourBandBoy;
cv::merge(channels, FourBandBoy);
As you haven't provided any sample raster images, I made 4 images, each 100x256, for a quick demonstration. Here they are:
-rw-r--r-- 1 mark staff 25600 21 Mar 10:44 band1.dat
-rw-r--r-- 1 mark staff 25600 21 Mar 10:44 band2.dat
-rw-r--r-- 1 mark staff 25600 21 Mar 10:44 band3.dat
-rw-r--r-- 1 mark staff 25600 21 Mar 10:44 band4.dat
Hopefully, you can see from the sizes that they are 100x256, single channel and 8-bit.
I the converted them to PGM per the original instructions:
{ printf "P5\n100 256\n255\n"; cat band1.dat; } > band1.pgm
{ printf "P5\n100 256\n255\n"; cat band2.dat; } > band2.pgm
{ printf "P5\n100 256\n255\n"; cat band3.dat; } > band3.pgm
{ printf "P5\n100 256\n255\n"; cat band4.dat; } > band4.pgm
which gives:
-rw-r--r-- 1 mark staff 25615 21 Mar 10:44 band1.pgm
-rw-r--r-- 1 mark staff 25615 21 Mar 10:44 band2.pgm
-rw-r--r-- 1 mark staff 25615 21 Mar 10:44 band3.pgm
-rw-r--r-- 1 mark staff 25615 21 Mar 10:44 band4.pgm
So, you can see the PGM header amounts to 15 bytes. The images look like this now:
I slightly modified the code:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <cstdio>
using namespace cv;
using namespace std;
int
main(int argc,char*argv[])
{
Mat b1 = imread("band1.pgm", IMREAD_UNCHANGED);
Mat b2 = imread("band2.pgm", IMREAD_UNCHANGED);
Mat b3 = imread("band3.pgm", IMREAD_UNCHANGED);
Mat b4 = imread("band4.pgm", IMREAD_UNCHANGED);
// Now merge
auto channels = std::vector<cv::Mat>{b1,b2,b3,b4};
cv::Mat BigBoy;
cv::merge(channels, BigBoy);
// Save
cv::imwrite("result.png",BigBoy);
}
And the result...
Hopefully you can see that the resulting image:
is blue where there was a lot of white in band1,
is green where there was a lot of white in band2,
is red where band3 was white
is transparent where band 4 was black

I don't feel like writing all the code and testing it like I ordinarily might so I'll just give you an outline of one way to do it.
Assume your images are WIDTHxHEIGHT in dimension and made of unsigned char data written consecutively without padding into files called band1.dat, band2.dat etc.
// Step 1: Allocate a buffer: raw = WIDTHxHEIGHT bytes
// Step 2: Load one band from disk into raw buffer
open band1.dat, read WIDTH*HEIGHT bytes into raw, close band1.dat
// Make a single band Mat from that data
cv::Mat band1(HEIGHT,WIDTH,CV_8UC1);
// Copy the raw data into it so we can re-use buffer
std::memcpy(band1.data,raw,WIDTH*HEIGHT);
// Repeat step 2 for bands 2-4 so you have 4 separate, single channel Mats
// Now merge the 4 individual channels into 4-band bad boy
auto channels = std::vector<cv::Mat>{band1, band2, band3, band4};
cv::Mat FourBandBoy;
cv::merge(channels, FourBandBoy);

Related

How to implement ESP8266 5 kHz PWM?

I need to realise a PWM output with 5 kHz +/- 5%. (Presumably due to a filter circuit into which this feeds over which I have no control.)
Is this realisable with a ESP8266 (ideally with NodeMCU)?
I realise that the software PWM of the ESP8266 has a maximum frequency of 1 kHz while the sigma-delta can be used to implement a PWM with a fixed frequency of about 300 kHz.
So is there a reliable way to achieve 5 kHz? I know some people experimented with the I2S peripheral for waveform output but I am unsure whether it can be used for 5kHz output.
Has anybody looked at into a similar problem before?
The essential code is:
#define qap 2 // Quick As Possible ... Duty cycle only 0, 50, 100%
#define HFreq 5150
#define pPulse D2 // a NodeMCU/ESP8266 GPIO PWM pin
analogWriteRange(qap); analogWriteFreq( HFreq ); analogWrite(pPulse, 1); // start PWM
TL;DR
Just did some crude benchamrks
// had HFreq=126400 with 75 KHz pulse at 80 MHz ESP clock, every 1 sec but proof of evidence lost
nominally with 80 MHz clock got
// 72.24 KHz 361178 2015061929
// 72.23 KHz 361163 2415062390
// 72.23 KHz 361133 2815062824
and
// 141.52 KHz 353809 2009395076
// 141.54 KHz 353846 2409395627
// 141.52 KHz 353806 2809395946
with 160 MHz clock
CAVEATS!!!
1. The duty cycle range is 2!
2. As well the system had no other conditioning, so other timing artifacts were still present from Serial IO etc. In particular instability due to the WDT and WiFi penultimately appeared. (Anyhow, presumably this is an issue only when the ESP8266 is under stress and duress.)
// 141.50 KHz 353754 619466806
// 141.52 KHz 353810 1019467038
// ...
// ad infinitum cum tempore finitum, infinitus est ad nauseum?
// ...
// 141.54 KHz 353857 735996888
//
// ets Jan 8 2013,rst cause:4, boot mode:(1,7)
//
//wdt reset
When using the following code to generate a 5 KHz square wave signal, the considerations above are not an issue and do not occur.
// ------------ test results for 80 MHz clock --------------
//
//
// PWM pulse test
//
// F_CPU: 80000000L
// ESP8266_CLOCK: 80000000UL
// PWM "freq.": 5150
//
//
// connect D1 to D2
//
//
// raw MPU
// frequency count cycle
// 0.00 KHz 1 407976267
// 4.74 KHz 9482 567976702
// 5.00 KHz 10007 727977137
// 5.00 KHz 10006 887977572
// 5.00 KHz 10006 1047978007
// 5.00 KHz 10007 1207978442
// 5.00 KHz 10006 1367978877
// 5.00 KHz 10006 1527979312
// 5.00 KHz 10007 1687979747
// 5.00 KHz 10006 1847980182
// 5.00 KHz 10006 2007980617
// 5.00 KHz 10007 2167981052
// 5.00 KHz 10006 2327981487
// 5.00 KHz 10006 2487981922
// 5.00 KHz 10007 2647982357 ...
//
// crude testing for 5KHz signal
// extracted from:
// highest frequency / shortest period pin pulse generate / detect test
//
// uses raw ESP8266 / NodeMCU V1.0 hardware primitive interface of Arduino IDE (no included libraries)
//
// timing dependencies: WDT, WiFi, I2S, I2C, one wire, UART, SPI, ...
//
// Arduino GPIO 16 5 4 0 2 14 12 13 15 3 1 0 1 2 3 4 5 ... 12 13 14 15 16
// NodeMCU D pin 0 1 2 3 4 5 6 7 8 9 10 3 10 4 9 2 1 ... 6 7 5 8 0
// | | | | | | | | | | |
// a WAKE | | F Tx1 | | Rx2 Tx2 Rx0 Tx0
// k (NO PWM or | | L blue | | | |
// a' interrupt) | S A * H | H | H | | * led's
// s red S D S S M S H
// * C A H C I I C
// L T L S M S
// K A K O O
// └ - - - - └----UART's----┘
// └--I2C--┘ └-----SPI------┘
//
// rules of engagement are obscure and vague for effects of argument values for the paramters of these functions:
// analogWriteRange(qap); analogWriteFreq( HFreq ); analogWrite(pPulse, 1);
//
// http://stackoverflow.com/questions/42112357/how-to-implement-esp8266-5-khz-pwm
//
// system #defines: F_CPU ESP8266_CLOCK
#define pInt D1 // HWI pin: NOT D0 ie. GPIO16 is not hardwared interrupt or PWM pin
#define pPulse D2 // PWM pulsed frequency source ... ditto D0 (note: D4 = blue LED)
#define countFor 160000000UL
#define gmv(p) #p // get macro value
#define em(p) gmv(p) // evaluate macro
#define qap 2 // minimal number of duty cycle levels (0, 50, 100% ) Quick As Possible ...
#define HFreq 5150 //((long int) F_CPU==80000000L ? 125000 : 250000) // ... to minimize time of a cycle period
// max values ^ and ^ found empirically
// had HFreq=126400 with 75 KHz pulse at 80 MHz ESP clock, every 1 sec but proof of evidence lost
#define infoTxt (String) \
"\n\n\t PWM pulse test " \
"\n F_CPU: " em(F_CPU) \
"\n ESP8266_CLOCK: " em(ESP8266_CLOCK) \
"\n PWM \"freq.\": " + HFreq + "\n" \
"\n\n connect " em(pInt) " to " em(pPulse) "\n" \
"\n\n raw MPU " \
" \n frequency count cycle "
long int oc=1, cntr=1;
unsigned long int tc=0;
void hwISR(){ cntr++; } // can count pulses if pInt <---> to pPulse
void anISR(){ tc=ESP.getCycleCount(); timer0_write( countFor + tc ); oc=cntr; cntr=1; }
void setup() { // need to still confirm duty cycle=50% (scope it or ...)
noInterrupts();
Serial.begin(115200); Serial.println(infoTxt); delay(10); // Serial.flush(); Serial.end(); // Serial timing?
analogWriteRange(qap); analogWriteFreq( HFreq ); analogWrite(pPulse, 1); // start PWM
pinMode( pInt, INPUT ); attachInterrupt(pInt, hwISR, RISING); // count pulses
timer0_isr_init(); timer0_attachInterrupt( anISR ); anISR(); //
interrupts();
}
void loop() { delay(10); if (oc==0) return;
Serial.println((String)" "+(oc/1000.0*F_CPU/countFor)+" KHz "+oc+" "+tc); oc=0; }
//
You can also use the hardware SPI interface which has an adjustable clock speed.
By writing continuous data, the output waveform appears on SCLK.
I've figured out the abovementioned while creating a knight rider effect with IC 74hc595 on ESP8266, using MicroPython (which is indeed slow, as being a script language).
It worked for me up to 4MHz SPI clock speed.
The disadvantage is, for permanent waveform, you need to write data to MOSI forever (as when SPI data buffer goes empty, there is no signal on SCLK anymore).

ctags: To get C function end line number

is it possible via ctags to get the function end line number as well
"ctags -x --c-kinds=f filename.c"
Above command lists the function definition start line-numbers. Wanted a way to get the function end line numbers.
Other Approaches:
awk 'NR > first && /^}$/ { print NR; exit }' first=$FIRST_LINE filename.c
This needs the code to be properly formatted
Example:
filename.c
1 #include<stdio.h>
2 #include<stdlib.h>
3 int main()
4 {
5 const char *name;
6
7 int a=0
8 printf("name");
9 printf("sssss: %s",name);
10
11 return 0;
12 }
13
14 void code()
15 {
16 printf("Code \n");
17 }
18
19 int code2()
20 {
21 printf("code2 \n");
22 return 1
23 }
24
Input: filename and the function start line no.
Example:
Input: filename.c 3
Output: 12
Input : filename.c 19
Output : 23
Is there any better/simple way of doing this ?
C/C++ parser of Universal-ctags(https://ctags.io) has end: field.
jet#localhost tmp]$ cat -n foo.c
1 int
2 main( void )
3 {
4
5 }
6
7 int
8 bar (void)
9 {
10
11 }
12
13 struct x {
14 int y;
15 };
16
[jet#localhost tmp]$ ~/var/ctags/ctags --fields=+ne -o - --sort=no foo.c
main foo.c /^main( void )$/;" f line:2 typeref:typename:int end:5
bar foo.c /^bar (void)$/;" f line:8 typeref:typename:int end:11
x foo.c /^struct x {$/;" s line:13 file: end:15
y foo.c /^ int y;$/;" m line:14 struct:x typeref:typename:int file:
awk to the rescue!
doesn't handle curly braces within comments but should handle blocks within functions, please give it a try...
$ awk -v s=3 'NR>=s && /{/ {c++}
NR>=s && /}/ && c && !--c {print NR; exit}' file
finds the matching brace for the first one after the specified start line number s.

converting images to indexed 2-bit grayscale BMP

First of all, my question is different to How do I convert image to 2-bit per pixel? and unfortunately its solution does not work in my case...
I need to convert images to 2-bit per pixel grayscale BMP format. The sample image has the following properties:
Color Model: RGB
Depth: 4
Is Indexed: 1
Dimension: 800x600
Size: 240,070 bytes (4 bits per pixel but only last 2 bits are used to identify the gray scales as 0/1/2/3 in decimal or 0000/0001/0010/0011 in binary, plus 70 bytes BMP metadata or whatever)
The Hex values of the beginning part of the sample BMP image:
The 3s represent white pixels at the beginning of the image. Further down there are some 0s, 1s and 2s representing black, dark gray and light gray:
With the command below,
convert pic.png -colorspace gray +matte -depth 2 out.bmp
I can get visually correct 4-level grayscale image, but wrong depth or size per pixel:
Color Model: RGB
Depth: 8 (expect 4)
Dimension: 800x504
Size: 1,209,738 bytes (something like 3 bytes per pixel, plus metadata)
(no mention of indexed colour space)
Please help...
OK, I have written a Python script following Mark's hints (see comments under original question) to manually create a 4-level gray scale BMP with 4bpp. This specific BMP format construction is for the 4.3 inch e-paper display module made by WaveShare. Specs can be found here: http://www.waveshare.com/wiki/4.3inch_e-Paper
Here's how to pipe the original image to my code and save the outcome.
convert in.png -colorspace gray +matte -colors 4 -depth 2 -resize '800x600>' pgm:- | ./4_level_gray_4bpp_BMP_converter.py > out.bmp
Contents of 4_level_gray_4bpp_BMP_converter.py:
#!/usr/bin/env python
"""
### Sample BMP header structure, total = 70 bytes
### !!! little-endian !!!
Bitmap file header 14 bytes
42 4D "BM"
C6 A9 03 00 FileSize = 240,070 <= dynamic value
00 00 Reserved
00 00 Reserved
46 00 00 00 Offset = 70 = 14+56
DIB header (bitmap information header)
BITMAPV3INFOHEADER 56 bytes
28 00 00 00 Size = 40
20 03 00 00 Width = 800 <= dynamic value
58 02 00 00 Height = 600 <= dynamic value
01 00 Planes = 1
04 00 BitCount = 4
00 00 00 00 compression
00 00 00 00 SizeImage
00 00 00 00 XPerlPerMeter
00 00 00 00 YPerlPerMeter
04 00 00 00 Colours used = 4
00 00 00 00 ColorImportant
00 00 00 00 Colour definition index 0
55 55 55 00 Colour definition index 1
AA AA AA 00 Colour definition index 2
FF FF FF 00 Colour definition index 3
"""
# to insert File Size, Width and Height with hex strings in order
BMP_HEADER = "42 4D %s 00 00 00 00 46 00 00 00 28 00 00 00 %s %s 01 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 00 00 00 00 55 55 55 00 AA AA AA 00 FF FF FF 00"
BMP_HEADER_SIZE = 70
BPP = 4
BYTE = 8
ALIGNMENT = 4 # bytes per row
import sys
from re import findall
DIMENTIONS = 1
PIXELS = 3
BLACK = "0"
DARK_GRAY = "1"
GRAY = "2"
WHITE = "3"
# sample data:
# ['P5\n', '610 590\n', '255\n', '<1 byte per pixel for 4 levels of gray>']
# where item 1 is always P5, item 2 is width heigh, item 3 is always 255, items 4 is pixels/colours
data = sys.stdin.readlines()
width = int(data[DIMENTIONS].strip().split(' ')[0])
height = int(data[DIMENTIONS].strip().split(' ')[1])
if not width*height == len(data[PIXELS]):
print "Error: pixel data (%s bytes) and image size (%dx%d pixels) do not match" % (len(data[PIXELS]),width,height)
sys.exit()
colours = [] # enumerate 4 gray levels
for p in data[PIXELS]:
if not p in colours:
colours.append(p)
if len(colours) == 4:
break
# it's possible for the converted pixels to have less than 4 gray levels
colours = sorted(colours) # sort from low to high
# map each colour to e-paper gray indexes
# creates hex string of pixels
# e.g. "0033322222110200....", which is 4 level gray with 4bpp
if len(colours) == 1: # unlikely, but let's have this case here
pixels = data[PIXELS].replace(colours[0],BLACK)
elif len(colours) == 2: # black & white
pixels = data[PIXELS].replace(colours[0],BLACK)\
.replace(colours[1],WHITE)
elif len(colours) == 3:
pixels = data[PIXELS].replace(colours[0],DARK_GRAY)\
.replace(colours[1],GRAY)\
.replace(colours[2],WHITE)
else: # 4 grays as expected
pixels = data[PIXELS].replace(colours[0],BLACK)\
.replace(colours[1],DARK_GRAY)\
.replace(colours[2],GRAY)\
.replace(colours[3],WHITE)
# BMP pixel array starts from last row to first row
# and must be aligned to 4 bytes or 8 pixels
padding = "F" * ((BYTE/BPP) * ALIGNMENT - width % ((BYTE/BPP) * ALIGNMENT))
aligned_pixels = ''.join([pixels[i:i+width]+padding for i in range(0, len(pixels), width)][::-1])
# convert hex string to represented byte values
def Hex2Bytes(hexStr):
hexStr = ''.join(hexStr.split(" "))
bytes = []
for i in range(0, len(hexStr), 2):
byte = int(hexStr[i:i+2],16)
bytes.append(chr(byte))
return ''.join(bytes)
# convert integer to 4-byte little endian hex string
# e.g. 800 => 0x320 => 00000320 (big-endian) =>20030000 (little-endian)
def i2LeHexStr(i):
be_hex = ('0000000'+hex(i)[2:])[-8:]
n = 2 # split every 2 letters
return ''.join([be_hex[i:i+n] for i in range(0, len(be_hex), n)][::-1])
BMP_HEADER = BMP_HEADER % (i2LeHexStr(len(aligned_pixels)/(BYTE/BPP)+BMP_HEADER_SIZE),i2LeHexStr(width),i2LeHexStr(height))
sys.stdout.write(Hex2Bytes(BMP_HEADER+aligned_pixels))
Edit: everything about this e-paper display and my code to display things on it can be found here: https://github.com/yy502/ePaperDisplay
This works for me in Imagemagick 6.9.10.23 Q16 Mac OSX Sierra
Input:
convert logo.png -colorspace gray -depth 2 -type truecolor logo_depth8_gray_rgb.bmp
Adding -type truecolor converts the image to RGB, but in gray tones as per the -colorspace gray. And the depth 2 creates only 4 colors in the histogram.
identify -verbose logo_depth8_gray_rgb.bmp
Image:
Filename: logo_depth8_gray_rgb.bmp
Format: BMP (Microsoft Windows bitmap image)
Class: DirectClass
Geometry: 640x480+0+0
Units: PixelsPerCentimeter
Colorspace: sRGB
Type: Grayscale
Base type: Undefined
Endianness: Undefined
Depth: 8/2-bit
Channel depth:
red: 2-bit
green: 2-bit
blue: 2-bit
Channel statistics:
Pixels: 307200
Red:
min: 0 (0)
max: 255 (1)
mean: 228.414 (0.895742)
standard deviation: 66.9712 (0.262632)
kurtosis: 4.29925
skewness: -2.38354
entropy: 0.417933
Green:
min: 0 (0)
max: 255 (1)
mean: 228.414 (0.895742)
standard deviation: 66.9712 (0.262632)
kurtosis: 4.29925
skewness: -2.38354
entropy: 0.417933
Blue:
min: 0 (0)
max: 255 (1)
mean: 228.414 (0.895742)
standard deviation: 66.9712 (0.262632)
kurtosis: 4.29925
skewness: -2.38354
entropy: 0.417933
Image statistics:
Overall:
min: 0 (0)
max: 255 (1)
mean: 228.414 (0.895742)
standard deviation: 66.9712 (0.262632)
kurtosis: 4.29928
skewness: -2.38355
entropy: 0.417933
Colors: 4 <--------
Histogram: <--------
12730: (0,0,0) #000000 black
24146: (85,85,85) #555555 srgb(85,85,85)
9602: (170,170,170) #AAAAAA srgb(170,170,170)
260722: (255,255,255) #FFFFFF white
Look at https://en.wikipedia.org/wiki/BMP_file_format#File_structure .
The problem is that you do not specify a color table. According to the wikipedia-article, those are mandatory if the bit depth is less than 8 bit.
Well done on solving the problem. You could consider also making a personal delegate, or custom delegate, for ImageMagick to help automate the process. ImageMagick is able to delegate formats it cannot process itself to delegates, or helpers, such as your 2-bit helper ;-)
Rather than interfere with the system-wide delegates, which probably live in /etc/ImageMagick/delegates.xml, you can make your own in $HOME/.magick/delegates.xml. Yours would look something like this:
<?xml version="1.0" encoding="UTF-8"?>
<delegatemap>
<delegate encode="epaper" command="convert "%f" +matte -colors 4 -depth 8 -colorspace gray pgm:- | /usr/local/bin/4_level_gray_4bpp_BMP_converter.py > out.bmp"/>
</delegatemap>
Then if you run:
identify -list delegate
you will see yours listed as a "known" helper.
This all means that you will be able to run commands like:
convert a.png epaper:
and it will do the 2-bit BMP thing automagically.
You can just use this:
convert in.jpg -colorspace gray +matte -colors 2 -depth 1 -resize '640x384>' pgm:- > out.bmp**
I too have this epaper display. After alot of trial and error, I was able to correctly convert the images using ImageMagick using the following command:
convert -verbose INPUT.BMP -resize 300x300 -monochrome -colorspace sRGB -colors 2 -depth 1 BMP3:OUTPUT.BMP

Beaglebone black (BBB) rev C 3.8.13-38-ARCH SPI doesn't work, Inappropriate ioctl for device

I have troubles with enabling SPI on BBB, ofc followed tutorial from the hipstercircuits.com.
I even installed a fresh arch linux to the uSD in case I really messed up system on eMMC.
My settings are:
Since SPI1 has issues with HDMI I disabled anything HDMI related I found.
Not sure about fdfile entry though, found it somewhere on the web. (I also tried without it)
Currently I'm working on the SD card if that matters.
uEnv.txt
optargs=quiet coherent_pool=1M fdtfile=am335x-boneblack.dtb capemgr.disable_partno=BB-BONELT-HDMI,BB-BONELT-HDMIN
I took dts file straight from the hipstercircuits.com and compiled it with alarm/dtc-overlay 1.4.1-1 installed via pacman.
After disabling HDMI in uEnv.txt
[root#alarm ~]# echo BB-SPI1-01 > /sys/devices/bone_capemgr.*/slots
went ok and I saw:
[root#alarm ~]# cat /sys/devices/bone_capemgr.9/slots
0: 54:PF---
1: 55:PF---
2: 56:PF---
3: 57:PF---
4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
5: ff:P-O-- Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
6: ff:P-O-- Bone-Black-HDMIN,00A0,Texas Instrument,BB-BONELT-HDMIN
7: ff:P-O-L Override Board Name,00A0,Override Manuf,BB-SPI1-01
I also tried echoing BB-SPIDEV0, BB-SPIDEV1 and BB-SPIDEV1A1 found here:
[root#alarm spi_a]# ls -l /lib/firmware | grep SPI
-rw-r--r-- 1 root root 1351 Jan 29 17:04 BB-SPI1-01-00A0.dtbo
-rw-r--r-- 1 root root 1185 Jan 25 01:06 BB-SPIDEV0-00A0.dtbo
-rw-r--r-- 1 root root 1185 Jan 25 01:06 BB-SPIDEV1-00A0.dtbo
-rw-r--r-- 1 root root 1185 Jan 25 01:06 BB-SPIDEV1A1-00A0.dtbo
Result of the spidev_test is always the same.
What is more interesting I didn't see anything about P9_29, P9_31 etc, which are part of SPI1, in pingroups:
[root#alarm ~]# cat /sys/kernel/debug/pinctrl/44e10800.pinmux/pingroups
registered pin groups:
group: pinmux_userled_pins
pin 21 (44e10854)
pin 22 (44e10858)
pin 23 (44e1085c)
pin 24 (44e10860)
group: pinmux_rstctl_pins
pin 20 (44e10850)
group: pinmux_i2c0_pins
pin 98 (44e10988)
pin 99 (44e1098c)
group: pinmux_i2c2_pins
pin 94 (44e10978)
pin 95 (44e1097c)
group: pinmux_mmc1_pins
pin 88 (44e10960)
group: pinmux_emmc2_pins
pin 32 (44e10880)
pin 33 (44e10884)
pin 0 (44e10800)
pin 1 (44e10804)
pin 2 (44e10808)
pin 3 (44e1080c)
pin 4 (44e10810)
pin 5 (44e10814)
pin 6 (44e10818)
pin 7 (44e1081c)
group: pinmux_userled_pins
pin 21 (44e10854)
pin 22 (44e10858)
pin 23 (44e1085c)
pin 24 (44e10860)
The spidevs are present in /dev
[root#alarm ~]# ls -l /dev | grep spi
crw------- 1 root root 153, 1 Jan 29 17:13 spidev1.0
crw------- 1 root root 153, 0 Jan 29 17:13 spidev1.1
To test the interface both python method mentioned in the tutorial and spidev_test.c (spidev_test.c) compiled on the BBB were used.
[root#alarm ~]# gcc spidev_test.c -o spidev_test
In case of python library there is no error but also nothing at the output - not even a clock signal on the SCL line.
spidev_test returns:
[root#alarm spi_a]# ./spidev_test
can't set spi mode: Inappropriate ioctl for device
Aborted (core dumped)
[root#alarm spi_a]# ./spidev_test -D /dev/spidev1.0
can't set spi mode: Inappropriate ioctl for device
Aborted (core dumped)
[root#alarm spi_a]# ./spidev_test -D /dev/spidev1.1
can't set spi mode: Inappropriate ioctl for device
Aborted (core dumped)
Do I have to make use of *.dts and *.dtb files provided at the beginning of the hipstercircuit's tutorial?
I probably screwed up sth easy. Any ideas what was it?
Did you get it working just like that?
All advices are welcome and will be very appreciated! ;)
I used this .dts and worked fine (both spidev1.0 and spidev1.1 on the spidev_test.c). There are some more lines than in the linux documentation which allow to enable second chip select for being used by SPI1 and properly configure the GPIO on the pin 42.
You should see now the spi pin muxing correctly.
/*
* Copyright (C) 2013 CircuitCo
*
* Virtual cape for SPI1 on connector pins P9.29 P9.31 P9.30 P9.28
*
* 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/;
/ {
compatible = "ti,beaglebone", "ti,beaglebone-black";
/* identification */
part-number = "BB-SPI1-01";
version = "00A0";
/* state the resources this cape uses */
exclusive-use =
/* the pin header uses */
"P9.31", /* spi1_sclk */
"P9.29", /* spi1_d0 */
"P9.30", /* spi1_d1 */
"P9.28", /* spi1_cs0 */
"P9.42", /* spi1_cs1 */
/* the hardware ip uses */
"spi1";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
/* default state has all gpios released and mode set to uart1 */
bb_spi1_pins: pinmux_bb_spi1_pins {
pinctrl-single,pins = <
0x190 0x33 /* mcasp0_aclkx.spi1_sclk, INPUT_PULLUP | MODE3 */
0x194 0x33 /* mcasp0_fsx.spi1_d0, INPUT_PULLUP | MODE3 */
0x198 0x13 /* mcasp0_axr0.spi1_d1, OUTPUT_PULLUP | MODE3 */
0x19c 0x13 /* mcasp0_ahclkr.spi1_cs0, OUTPUT_PULLUP | MODE3 */
0x164 0x12 /* eCAP0_in_PWM0_out.spi1_cs1 OUTPUT_PULLUP | MODE2 */
0x1A0 0x32 /* Other P42 pin, INPUT_PULLUP */
>;
};
};
};
fragment#1 {
target = <&spi1>; /* spi1 is numbered correctly */
__overlay__ {
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bb_spi1_pins>;
#address-cells = <1>;
#size-cells = <0>;
spi1_0{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <0>;
spi-max-frequency = <16000000>;
};
spi1_1{
#address-cells = <1>;
#size-cells = <0>;
compatible = "spidev";
reg = <1>;
spi-max-frequency = <16000000>;
};
};
};};
I think the problem is the ioctl.h.
When I search for 'iotl.h', the result is as follows,
/usr/include/arm-linux-gnueabihf/sys/ioctl.h
/usr/include/arm-linux-gnueabihf/asm/ioctl.h
/usr/include/linux/ioctl.h
/usr/include/linux/hdlc/ioctl.h
/usr/include/linux/mmc/ioctl.h
/usr/include/asm-generic/ioctl.h
So there is no corresponding sys/ioctl.h
I am trying to find the correct ioctl.h

Golang append memory allocation VS. STL push_back memory allocation

I compared the Go append function and the STL vector.push_back and found that different memory allocation strategy which confused me. The code is as follow:
// CPP STL code
void getAlloc() {
vector<double> arr;
int s = 9999999;
int precap = arr.capacity();
for (int i=0; i<s; i++) {
if (precap < i) {
arr.push_back(rand() % 12580 * 1.0);
precap = arr.capacity();
printf("%d %p\n", precap, &arr[0]);
} else {
arr.push_back(rand() % 12580 * 1.0);
}
}
printf("\n");
return;
}
// Golang code
func getAlloc() {
arr := []float64{}
size := 9999999
pre := cap(arr)
for i:=0; i<size; i++ {
if pre < i {
arr = append(arr, rand.NormFloat64())
pre = cap(arr)
log.Printf("%d %p\n", pre, &arr)
} else {
arr = append(arr, rand.NormFloat64())
}
}
return;
}
But the memory address is invarient to the increment of size expanding, this really confused me.
By the way, the memory allocation strategy is different in this two implemetation (STL VS. Go), I mean the expanding size. Is there any advantage or disadvantage? Here is the simplified output of code above[size and first element address]:
Golang CPP STL
2 0xc0800386c0 2 004B19C0
4 0xc0800386c0 4 004AE9B8
8 0xc0800386c0 6 004B29E0
16 0xc0800386c0 9 004B2A18
32 0xc0800386c0 13 004B2A68
64 0xc0800386c0 19 004B2AD8
128 0xc0800386c0 28 004B29E0
256 0xc0800386c0 42 004B2AC8
512 0xc0800386c0 63 004B2C20
1024 0xc0800386c0 94 004B2E20
1280 0xc0800386c0 141 004B3118
1600 0xc0800386c0 211 004B29E0
2000 0xc0800386c0 316 004B3080
2500 0xc0800386c0 474 004B3A68
3125 0xc0800386c0 711 004B5FD0
3906 0xc0800386c0 1066 004B7610
4882 0xc0800386c0 1599 004B9768
6102 0xc0800386c0 2398 004BC968
7627 0xc0800386c0 3597 004C1460
9533 0xc0800386c0 5395 004B5FD0
11916 0xc0800386c0 8092 004C0870
14895 0xc0800386c0 12138 004D0558
18618 0xc0800386c0 18207 004E80B0
23272 0xc0800386c0 27310 0050B9B0
29090 0xc0800386c0 40965 004B5FD0
36362 0xc0800386c0 61447 00590048
45452 0xc0800386c0 92170 003B0020
56815 0xc0800386c0 138255 00690020
71018 0xc0800386c0 207382 007A0020
....
UPDATE:
See comments for Golang memory allocation strategy.
For STL, the strategy depends on the implementation. See this post for further information.
Your Go and C++ code fragments are not equivalent. In the C++ function, you are printing the address of the first element in the vector, while in the Go example you are printing the address of the slice itself.
Like a C++ std::vector, a Go slice is a small data type that holds a pointer to an underlying array that holds the data. That data structure has the same address throughout the function. If you want the address of the first element in the slice, you can use the same syntax as in C++: &arr[0].
You're getting the pointer to the slice header, not the actual backing array. You can think of the slice header as a struct like
type SliceHeader struct {
len,cap int
backingArray unsafe.Pointer
}
When you append and the backing array is reallocated, the pointer backingArray will likely be changed (not necessarily, but probably). However, the location of the struct holding the length, cap, and pointer to the backing array doesn't change -- it's still on the stack right where you declared it. Try printing &arr[0] instead of &arr and you should see behavior closer to what you expect.
This is pretty much the same behavior as std::vector, incidentally. Think of a slice as closer to a vector than a magic dynamic array.

Resources