Beagle Bone Black PRU Device Overlay for fast IO does not work - overlay

I desperately try to get the PRU on my BBB working. By working I mean that I would want to use the pins P8 39-46 (GPIO2[6-13]) as a fast output controlled by the PRU.
I installed the debian for BBB (2 weeks ago, should be current) on SD.
Then I started with the following article: http://www.element14.com/community/community/designcenter/single-board-computers/next-gen_beaglebone/blog/2013/05/22/bbb--working-with-the-pru-icssprussv2
doing so, I got the PRU working with the LED example as well as with pin P8[12].
Now I try to get the other pins working. I started all over by just making a little change to the original am335x-boneblack.dtb. I just activated the PRU.
I did not change the LED heartbeat as well as pin P8.12.
Then I disabled HDMI in uEnv.txt
My "slots" look like this now:
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
I stumbled upon this post here: https://groups.google.com/forum/#!topic/beagleboard/JRG36bOURfk
EXACTLY what I would want to have, so I took the dts ( the second one) , compiled it, copied it to /lib/firmware and loaded it. "slots" says the overlay was loaded.
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-PRU-IO
BB-PRU-IO is me.
dmesg says:
... part_number 'BB-PRU-IO', version 'N/A'
... slot #7: generic override
... bone: Using override eeprom data at slot 7
... slot #7: 'Override Board Name,00A0,Override Manuf,BB-PRU-IO'
... slot #7: Requesting part number/version based 'BB-PRU-IO-00A0.dtbo
... slot #7: Requesting firmware 'BB-PRU-IO-00A0.dtbo' for board-name 'Override Board Name', version '00A0'
... slot #7: dtbo 'BB-PRU-IO-00A0.dtbo' loaded; converting to live tree
... slot #7: #2 overlays
... slot #7: Applied #2 overlays.
Looking good I would say.
The problem is the pinmux does not seam to be impressed:
cat pins | grep 8a4
=> pin 41 (44e108a4) 0000002f pinctrl-single
This is MODE 7 (GPIO Out). Not what I wanted. For all of pins I intended to switch to PRU Mode 5.
Now I tried the delivered dtbo's for the PRU 01,02 in /lib/firmware
PRU-01.dtbo seems to be a fitting example. Only the Pin is different (P9.27).
I loaded it and changed the PRU code example.
The pins did not show the expected result:
pin 105 (44e109a4) 00000027 pinctrl-single
When I run the modified testprogram from the first articel my osci shows a flatline.
I tried PRU-02.dtbo.
At least the pins showed the expected result:
pin 105 (44e109a4) 00000025 pinctrl-single
When I start my little test program I get a "bus error"
dmesg has several lines. the important ones I would say are:
[ 119.258978] WARNING: at arch/arm/mach-omap2/omap_hwmod.c:2096 _enable+0x101/0x174()
[ 119.259004] omap_hwmod: pruss: enabled state can only be entered from initialized, idle, or disabled state
[ 119.259027] Modules linked in: g_multi libcomposite btusb bluetooth rfkill uio_pruss mt7601Usta(O)
.... several trace messages
[ 119.272382] pru-rproc 4a300000.prurproc: #8 PRU interrupts registered
[ 119.272445] pru-rproc 4a300000.prurproc: Failed to read events array
[ 119.287545] pru-rproc: probe of 4a300000.prurproc failed with error -22
PRU-02 does more than PRU-01 (what I do not understand). And it does not seem to work for me.
Now I am kind of helpless.
Any ideas on that?
EDIT:
I did what you should not do. I changed the pinmux setting in the am335x-boneblack.dtb file. I just added:
0xA0 0x05
0xA4 0x05
0xA8 0x05
0xAC 0x05
0xB0 0x05
0xB4 0x05
0xB8 0x05
0xBC 0x05
to pinmux_userled_pins {
pinctrl-single,pins = <
Now it works, but I am not happy. I still would appreciate a regular overlay file.

OK I got it working:
just enable the pruss in the am335x-boneblack.dtb (convert to dts. do the changes as described in the article mentioned in the original post)
Got to the website : http://kilobaser.com/blog/2014-07-28-beaglebone-black-devicetreeoverlay-generator#dtogenerator and let the site create dts files for the various pins in my case P8 46-39. Using a single DTS(DTBO) File for each individual pin works but requires 8 dtbos loaded => I moved all of them into one DTS File.
this is it:
/dts-v1/;
/plugin/;
/{
compatible = "ti,beaglebone", "ti,beaglebone-black";
part_number = "BS_PINMODE_PRU_OUT";
exclusive-use =
"P8.46",
"P8.45",
"P8.44",
"P8.43",
"P8.42",
"P8.41",
"P8.40",
"P8.39",
"pr1_pru1_pru_r30_6",
"pr1_pru_pru1_r30_7",
"pr1_pru1_pru_r30_4",
"pr1_pru1_pru_r30_5",
"pr1_pru1_pru_r30_2",
"pr1_pru1_pru_r30_3",
"pr1_pru1_pru_r30_0",
"pr1_pru1_pru_r30_1";
fragment#0 {
target = <&am33xx_pinmux>;
__overlay__ {
bs_pinmode_pru_out: pinmux_bs_pinmode_pru_out {
pinctrl-single,pins = <0x0a4 0x5 0x0a0 0x5 0x0ac 0x5 0x0a8 0x5 0x0b4 0x5 0x0b0 0x5 0x0bc 0x5 0x0b8 0x5>;
};
};
};
fragment#1 {
target = <&ocp>;
__overlay__ {
bs_pinmode_pru_out_pinmux {
compatible = "bone-pinmux-helper";
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&bs_pinmode_pru_out>;
};
};
};
};
I named the file bspm_pru_out-00A0.dts, compiled it to bspm_pru_out-00A0.dtbo and placed it it in the /lib/firmware.
You can load it via /boot/uEnv.txt or via echo... in a rc.local file... whatever you like.

Related

"/pl061#9030000:clocks: cell 0 is not a phandle reference" when compiling a dts file

I used "-machine dumpdtb=dtb.dtb" in qemu command to extract dtb file of the arm 'virt' machine. Then I converted the dtb file to dts file using dtc. And I tried to make that dts file backto dtb. But I'm seeing a warning message like this (only showing the first warning).
dtb.dts:284.3-21: Warning (clocks_property): /pl061#9030000:clocks: cell 0 is not a phandle reference
The warning comes from the line in the dts
pl061#9030000 {
phandle = <0x8003>;
clock-names = "apb_pclk";
clocks = <0x8000>; <==== this line
interrupts = <0x00 0x07 0x04>;
gpio-controller;
#gpio-cells = <0x02>;
compatible = "arm,pl061\0arm,primecell";
reg = <0x00 0x9030000 0x00 0x1000>;
};
I've looked at Documentation/devicetree/bindings/gpio/pl061-gpio.yaml but there is no explanation about the property clocks. I guess it's the clock frequency for the gpio but somehow the dtc program thinks it is a phandle. and I couldn't find any use of 'clocks' in the pl061 driver. Can I just safely ignore that error?
This is a phandle to the /apb-pclk node elsewhere in the dtb. The "clocks" property is part of the "arm,primecell" binding, documented here:
https://www.kernel.org/doc/Documentation/devicetree/bindings/arm/primecell.txt

Grove I2C display not working on Raspberry Pi 3B

I only have my RPi 3B and a I²C display, I don't own any GrovePi hat and I want to show some text to the said display. Is there a way to make it work?
My display.
i2cdetect -y 1 shows this result, meaning the RPi is detecting the I²C display and it should work. But nothing seemed to be showing on the display, except for the full block on the first row.
I've tried literally everything on the internet, some library worked (as in throwing no errors) but the display still stays the same, full block on the first row.
I've installed python3, smbus, smbus2 and i2c-tools. I've changed the address to 3e.
My most recent *.py file. It does write 'LCD printing' yet nothing else works.
I don't find a way to change the contrast of the LCD (no potentiometer or whatsoever)
#!/usr/bin/python3
import smbus2 as smbus
import time
# Define some device parameters
I2C_ADDR = 0x3e # I2C device address, if any error, change this address to 0x3f
LCD_WIDTH = 16 # Maximum characters per line
# Define some device constants
LCD_CHR = 1 # Mode - Sending data
LCD_CMD = 0 # Mode - Sending command
LCD_LINE_1 = 0x80 # LCD RAM address for the 1st line
LCD_LINE_2 = 0xC0 # LCD RAM address for the 2nd line
LCD_LINE_3 = 0x94 # LCD RAM address for the 3rd line
LCD_LINE_4 = 0xD4 # LCD RAM address for the 4th line
LCD_BACKLIGHT = 0x08 # On
ENABLE = 0b00000100 # Enable bit
# Timing constants
E_PULSE = 0.0005
E_DELAY = 0.0005
# Open I2C interface
# bus = smbus.SMBus(0) # Rev 1 Pi uses 0
bus = smbus.SMBus(1) # Rev 2 Pi uses 1
def lcd_init():
# Initialise display
lcd_byte(0x33, LCD_CMD) # 110011 Initialise
lcd_byte(0x32, LCD_CMD) # 110010 Initialise
lcd_byte(0x06, LCD_CMD) # 000110 Cursor move direction
lcd_byte(0x0C, LCD_CMD) # 001100 Display On,Cursor Off, Blink Off
lcd_byte(0x28, LCD_CMD) # 101000 Data length, number of lines, font size
lcd_byte(0x01, LCD_CMD) # 000001 Clear display
time.sleep(E_DELAY)
def lcd_byte(bits, mode):
# Send byte to data pins
# bits = the data
# mode = 1 for data
# 0 for command
bits_high = mode | (bits & 0xF0) | LCD_BACKLIGHT
bits_low = mode | ((bits << 4) & 0xF0) | LCD_BACKLIGHT
# High bits
bus.write_byte(I2C_ADDR, bits_high)
lcd_toggle_enable(bits_high)
# Low bits
bus.write_byte(I2C_ADDR, bits_low)
lcd_toggle_enable(bits_low)
def lcd_toggle_enable(bits):
# Toggle enable
time.sleep(E_DELAY)
bus.write_byte(I2C_ADDR, (bits | ENABLE))
time.sleep(E_PULSE)
bus.write_byte(I2C_ADDR, (bits & ~ENABLE))
time.sleep(E_DELAY)
def lcd_string(message, line):
# Send string to display
message = message.ljust(LCD_WIDTH, " ")
lcd_byte(line, LCD_CMD)
for i in range(LCD_WIDTH):
lcd_byte(ord(message[i]), LCD_CHR)
if __name__ == '__main__':
lcd_init()
while True:
# Send some test
lcd_string("Hello ", LCD_LINE_1)
lcd_string(" World", LCD_LINE_2)
print('LCD printing!')
time.sleep(3)

Linux Device Tree to Hardware Mapping

I was wondering how some specific details in the device relate to the hardware and where to find this information(like schematic, datasheet etc).
An example of a usb node is given below:
In the picture above I was wondering how do you find CLK_BUS_OHCI2 or RST_BUS_EHCI2 on the hardware. If you go to the include files you get a value (CLK_BUS_OHCI2 = 39), but I am not sure how that relates to actual hardware. Like which register or which pin etc.
Nowadays I'm working with a similar platform, Allwinner A64 and I'm trying to understand how DTS, clocks, resets work. Fortunately your question came up in the search engine results. Gaurav Pathak's answer clarified most of the things for me and I want to extend a little bit from his point to help those who are trying to fill in the gap about bridging DTS and hardware.
I will refer to Linux kernel 5.7 and Allwinner A64 User Manual (v1.1).
There's a resemblance between uart4 and ehci2 in the means of node definition; for instance, we have property of clocks and resets in both of them. But ccu clock output usage were implemented different.
Let's take a closer look at uart4 node.
uart4: serial#1c29000 {
compatible = "snps,dw-apb-uart";
reg = <0x01c29000 0x400>;
interrupts = <GIC_SPI 4 IRQ_TYPE_LEVEL_HIGH>;
reg-shift = <2>;
reg-io-width = <4>;
clocks = <&ccu CLK_BUS_UART4>;
resets = <&ccu RST_BUS_UART4>;
status = "disabled";
};
Now we already know that CLK_BUS_UART4 is included from include/dt-bindings/clock/sun50i-a64-ccu.h.
<&ccu CLK_BUS_UART4>
A further search for CLK_BUS_UART4 reveals that include/dt-bindings/clock/sun50i-a64-ccu.h is also indirectly (through drivers/clk/sunxi-ng/ccu-sun50i-a64.h) included from drivers/clk/sunxi-ng/ccu-sun50i-a64.c.
Then it was possible to refer to CLK_BUS_UART4 like below (L807 # ccu-sun50i-a64.c)
[CLK_BUS_UART4] = &bus_uart4_clk.common.hw
But what is bus_uart4_clk? Let's see.
It is defined at L381 # ccu-sun50i-a64.c. This is how it looks:
static SUNXI_CCU_GATE(bus_uart4_clk, "bus-uart4", "apb2",
0x06c, BIT(20), 0);
SUNXI_CCU_GATE is a macro to manage gating register of Clock Control Unit. 4th argument, 0x06c refers to the register offset and 5th argument BIT(20) implies the Nth bit (20, in this case) at the offset of 0x06c is adjusted to drive bus_uart4_clk.
Same thing applies for the resets property. To give a specific example; just search for RST_BUS_UART4 and 0x2d8 at Linux kernel source then look at the bottom of Page 142 of the A64 User Manual.
I hope there were not too much nonsense... Please correct me if I'm wrong.
Well, as far as I know in the below structure
ehci2: usb#01c1c000 {
compatible = "allwinner,sun8i-h3-ehci", "generic-ehci";
reg = <0x01c1c000 0x100>;
interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>;
resets = <&ccu RST_BUS_EHCI2>, <&ccu RST_BUS_OHCI2>;
phys = <&usbphy 2>;
phy-names = "usb";
status = "disabled";
};
clocks = <&ccu CLK_BUS_EHCI2>, <&ccu CLK_BUS_OHCI2>; represents consumer clocks i.e. input clocks and is called "phandle + clock specifier pairs". As you mentioned CLK_BUS_OHCI2 has value 39, that means USB controller will take input clock from the output 39 of ccu clock source.
In the dtsi file from where you posted the above screenshot, there should be a structure that defines the ccu for example like this below:
ccu: clk#01c20060 {
#clock-cells = <1>;
compatible = "allwinner,sun7i-a20-ahb-gates-clk";
reg = <0x01c20060 0x8>;
clocks = <&ahb>;
clock-output-names = "ahb_usb0", "ahb_ehci0",
"ahb_ohci0", "ahb_ehci1", "ahb_ohci1",
"ahb_ss", "ahb_dma", "ahb_bist", "ahb_mmc0",
"ahb_mmc1", "ahb_mmc2", "ahb_mmc3", "ahb_ms",
"ahb_nand", "ahb_sdram", "ahb_ace",
"ahb_emac", "ahb_ts", "ahb_spi0", "ahb_spi1",
"ahb_spi2", "ahb_spi3", "ahb_sata",
"ahb_hstimer", "ahb_ve", "ahb_tvd", "ahb_tve0",
"ahb_tve1", "ahb_lcd0", "ahb_lcd1", "ahb_csi0",
"ahb_csi1", "ahb_hdmi1", "ahb_hdmi0",
"ahb_de_be0", "ahb_de_be1", "ahb_de_fe0",
"ahb_de_fe1", "ahb_gmac", "ahb_ehci2",
"ahb_mali";
};
In the above structure there are multiple clock source outputs, so clock source 39 should be utilised by the above USB controller for taking clock input, note that #clock-cells = <1>; represents multiple clock output and #clock-cells = <0>; is for single clock output.
The ccu structure is just an example.

Hardware interrupt between Raspberry pi and Atmega 328

I have connected my RPI and atmega328 together in order to control the start of an event on my arduino. In order to do so, GPIO 25 (RPI) is connected directly to pin7 (Arduino PD7). I've got a python script on the RPI witch set the GPIO 25 to high then back to LOW:
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(25, GPIO.OUT)
GPIO.output(25, 1)
#Do some stuff
GPIO.output(25, 0)
The arduino is waiting in a loop for either a physical button to be pressed or the pin7 to be set to HIGH by the RPI:
const int interrupt = 7;
const int button = 13;
const int led = 9;
void setup() {
Serial.begin(9600);
pinMode(interrupt, INPUT);
pinMode(button,INPUT);
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
bool on = false;
bool buttonOn = false;
while (!on || !buttonOn) {
on = digitalRead(interrupt);
buttonOn = digitalRead(button);
digitalWrite(led, LOW);
}
digitalWrite(led, HIGH);
delay(1000);
}
Now unfortunately this doesn't work. I have checked the logic level of the atmega328 (https://learn.sparkfun.com/tutorials/logic-levels) and it seems that 3.3V is good enough for HIGH signal.
Am I missing something with the pull up /pull down resistance? I know the PD7 on the atmega is specified as follow:
Port D is an 8-bit bi-directional I/O port with internal pull-up
resistors (selected for each bit). The Port D output buffers have
symmetrical drive characteristics with both high sink and source
capability. As inputs, Port D pins that are externally pulled low will
source current if the pull-up resistors are activated. The Port D pins
are tristated when a reset condition becomes active, even if the clock
is not running.
EDIT:
I have done more testing and I am getting the HIGH or LOW value correctly. It seems that the issue comes from the:
while ((!on) || (!buttonOn)) {
Is there an issue with Arduino and the OR operator in a while loop? Even when one condition is true and the other one is false, it never goes out of the loop.
while ((!on) || (!buttonOn)) {
}
That loop will run as long as one of the variables is false.
Yesterday I was for some reason thinking that you were reading the interrupt pin twice when reading your code.
3.3 v output should be ok to turn the Arduino input high.
You can have a wiring problem or your raspberry pi can be so fast that the arduino misses the pulse.
Change your program on the raspberry pi to leave the output high for so long (e.g. 10) seconds that you can measure it with a multimeter to see that you are setting the right pin.
Does the Arduino now see the input?

is Atom-32bit in mode protected after a reset?

I work on Atom-32bit-intel, I have to port MicroC OS II, so there is no code to make any configuration on the Atom (No GDT, no LDT...):
my question is more about the state of the Atom-32bit after a reset, is the Atom in protecte mode or not ? and the most important how do i check which mode is it (which registers have to be checked nad how)?
Remark:
The CR0.PE = 1 (I checked it), is that enough to prove that the Atom is in protected mode ?
************ UPDATE : *****************
/*Read the IDTR*/
sidt (idt_ptr)
/*Read the GDTR*/
sgdt (gdt_ptr)
So I tried just to use IDT's address to link my ISR to the IDT :
fill_interrupt(ISR_Nbr,(unsigned int) isr33, 0x08, 0x8E);
static void fill_interrupt(unsigned char num, unsigned int base, unsigned short sel, unsigned char flags)
{
unsigned short *Interrupt_Address;
/*address = idt_ptr.base + num * 8 byte*/
Interrupt_Address = (unsigned short *)(idt_ptr.base + num*8);
*(Interrupt_Address) = base&0xFFFF;
*(Interrupt_Address+1) = sel;
*(Interrupt_Address+1) = (flags>>8)&0xFF00;
*(Interrupt_Address+1) = (base>>16)&0xFFFF;
}
my ISR a imple one :
isr33:
nop
nop
cli
push %ebp //save the context to swith back
mov %esp,%ebp
pop %ebp //Return to the calling function
sti
ret
Chapter 9 of volume 3 of the Intel Software Developer's Manual says that the reset value of CR0 is 60000010H. As you can see, bit 0, aka PE, is clear.
Regardless, you can setup the descriptor tables in Protected Mode as well as in Real Mode. You just have to be more careful about it.
I suggest you check if the BIOS or OS are setting this bit at a stage before you read it.
Atom is x86 instruction set, and as such, should be starting in real mode for compatibility. I don't have one on hand to test with though.
Resolved, I use N450 Atom board, it has already a BIOS, the BIOS configures the board in Protected Mode.