**** BEGIN LOGGING AT Sat Jul 27 02:59:57 2019 Jul 27 04:23:01 how can I interact with the PRU directly from C? Jul 27 04:57:15 do I just open the device and read from it and write to it in particular patterns? Jul 27 04:57:23 define "interact" ? Jul 27 04:57:33 the stuff I'm doing with py-uio Jul 27 04:57:49 load some code and write to the DRAM Jul 27 04:57:55 there's libprussdrv but it sucks in my opinion... I hope to write a better C/C++ library for it some time Jul 27 04:58:03 and start it and check whether it's halted Jul 27 04:58:32 I'm trying to figure out how you managed to do something this low-level in pure Python Jul 27 04:58:37 my suggestion would be to use py-uio to initialize the subsystem and start your application, and then just open() and mmap() it in C to access its DRAM Jul 27 04:59:07 I mean... all you need is mmap(), and read()/write() to a file descriptor for managing interrupts Jul 27 04:59:12 python has those things Jul 27 04:59:16 mmap which? Jul 27 04:59:40 the device directly? Jul 27 05:00:09 the physical memory regions of the uio device, which in this case are 0. all of pruss 1. the chunk of main memory reserved for pru's use by the uio_pruss driver Jul 27 05:00:50 can I start it and wait for it to stop with C? Jul 27 05:02:08 and I used ctypes structures to model memory-mapped registers (e.g. https://github.com/mvduin/py-uio/blob/master/src/uio/ti/icss/core.py ) and then the .from_buffer class method available on each ctypes type to create an instance of it that's backed by the actual mmap()ed registers Jul 27 05:02:24 you can do anything py-uio does, there just isn't a library for it as nice as py-uio yet Jul 27 05:02:36 like I said, there's libprussdrv, but it just sucks Jul 27 05:02:44 I don't mind doing it myself Jul 27 05:03:02 I guess I can see if I can share my C++ headers for it Jul 27 05:03:46 I've been looking at core.py Jul 27 05:04:45 so I can just read from mmapped memory as a particular C struct? Jul 27 05:14:24 I'm cleaning up a pru loader I wrote in C++ (which the headers I had already made a while ago, based on which I created the structures in py-uio, while the initialization code is conversely actually based on py-uio) Jul 27 05:18:31 how did you figure out what the structs look like? Jul 27 05:18:43 libprussdrv? Jul 27 05:19:18 documentation Jul 27 05:20:12 where can I find that documentation? Jul 27 05:30:31 see link in private message for code Jul 27 05:30:46 documentation? mostly various versions of the AM335x Technical Reference Manual Jul 27 05:30:56 both rev C and the latest are useful Jul 27 05:31:22 the latest version is probably adequate Jul 27 05:32:19 oh btw, ignore the stuff in the uapi directory and the Uio::set_pinctrl_state method, that relies on custom kernel patches that I still need to try to suggest upstream Jul 27 05:34:29 (they allow users of an uio device to use an ioctl() to switch between multiple pinctrl states declared in DT for the device) Jul 27 05:34:44 what are pinctrl states? Jul 27 05:35:04 like, sets of pin configuration, like you're doing with config-pin Jul 27 05:35:39 I needed it in one test because I wanted to do some initialization before muxing pins, to ensure pins would not get driven with the wrong value Jul 27 05:36:17 and I don't use cape-universal (which is the runtime pinmux switching thing you control via config-pin) Jul 27 06:17:09 how do you calculate the size to pass to mmap? Jul 27 06:28:55 specifically, why the `size += -size & 0xfff;`? Jul 27 06:55:26 I think I'm starting to understand the reference manual Jul 27 06:55:32 how do I reset the PRU? Jul 27 07:15:51 nevermind, I think I figured it out Jul 27 08:01:21 uhh, did you look at my code? Jul 27 08:02:44 yeah, some Jul 27 08:02:54 I'm trying to write my own code to do the parts of it I need Jul 27 08:03:22 I can't seem to mmap either just the core control part or just the IRAM Jul 27 08:04:23 you can't, and I already told you that Jul 27 08:04:33 oh, sorry, you did? Jul 27 08:05:05 I probably didn't understand it at the time Jul 27 08:08:11 https://pastebin.com/w0Q13msa Jul 27 08:08:42 ah! Jul 27 08:08:50 yes, I definitely didn't understand mmap then Jul 27 08:10:34 and now I understand why that's a "really ugly hack" Jul 27 08:11:21 :D Jul 27 08:11:44 why not at least let the offset indicate which region to map? Jul 27 08:11:51 that's at least sort of what the offset is for Jul 27 08:13:16 it does, but only in the sense of offset = region_index * PAGE_SIZE ... the multiplication by PAGE_SIZE is because glibc actually divides the offset (and length, I think) by PAGE_SIZE before doing the syscall to the kernel Jul 27 08:14:34 oh! Jul 27 08:14:38 it would have been much nicer if all of the device's memory regions would be considered part of one device-specific virtual memory space (e.g. using a "ranges" declaration in DT) from which you'd mmap subranges Jul 27 08:14:45 I misread that -- I thought the region index was passed as the size Jul 27 08:14:45 that's how it works with drm devices, which I much prefer Jul 27 08:14:53 no, the size is still size Jul 27 08:15:10 but the size can only be the whole thing? Jul 27 08:15:41 how big is the whole thing? Jul 27 08:15:45 it usually is, but you can mmap() less than the whole region (but only the initial part, since you don't have a working offset parameter) Jul 27 08:15:53 got it Jul 27 08:16:15 (see also Uio::mmap() in src/uio.h ) Jul 27 08:18:22 the whole thing? pru-icss you mean? sizeof(Pruss) from #include "ti/icss.h" in my code :P Jul 27 08:20:59 the last part just says "Reserved" in the manual, so it's hard to tell how big the whole thing is Jul 27 08:21:09 but I guess I don't need past the end of IRAM anyway Jul 27 08:21:15 correct Jul 27 08:21:56 technically it is 0x80000 kinda sorta maybe on some platforms... but I don't know if it's even declared to be that big in the DT Jul 27 08:22:05 and you can't mmap() it bigger than whatever is declared in DT Jul 27 08:22:15 you can also query that information in sysfs Jul 27 08:22:25 e.g. using libudev Jul 27 08:22:42 but that's a bit silly, just mmap() the size you actually need Jul 27 08:24:23 I feel a little silly asking this, but what's a DT? Jul 27 08:25:31 msync() isn't working... Jul 27 08:27:24 I'm supposed to pass it the same size I passed to mmap(), right? Jul 27 08:29:04 using msync() makes absolutely no sense Jul 27 08:29:12 it only applies to file-backed memory Jul 27 08:29:19 ...oh Jul 27 08:29:23 (it also does nothing on linux iirc) Jul 27 08:29:30 actually it might Jul 27 08:29:41 not sure Jul 27 08:29:42 well, that explains that part, but that means I'm doing something else wrong... Jul 27 08:30:04 man page says it does nothing if you make it asynchronous Jul 27 08:30:45 ah yeah, MS_SYNC makes it basically equivalent to fsync() on the underlying file Jul 27 08:30:50 on linux Jul 27 08:30:56 not on all platforms in general Jul 27 08:32:30 regardless, it's abpout flushing your changes to the filesystem... it's not relevant here. in this case, the "memory" you map into your process with mmap() directly corresponds to physical memory / memory-mapped I/O Jul 27 08:33:16 doing a load/store to your mmap()ed region directly results in a read- or write-transaction being sent to PRUSS via the SoC's interconnects Jul 27 08:33:28 all right Jul 27 08:36:44 what do I need to do to start the PRU? Jul 27 08:37:15 I'm clearing PCTR_RST_VAL and setting EN and SOFT_RST_N Jul 27 08:38:00 dude just read my src/loader.cc .. it's like, one page of code Jul 27 08:38:13 fine, fine Jul 27 08:39:35 and/or read the comments in include/ti/icss/core.h .. I've also done a fair bit of empirical science to determine details that are not documented clearly (or at all, usually), and wrote those up in the comments Jul 27 08:41:25 ah, I just cleared the whole control short, and it works now Jul 27 08:42:22 btw to increase the readability of my code, if you have the ability to customize syntax highlighting in whatever editor you use, consider adding a rule to highlight "let" as a keyword... it will probably help ;) Jul 27 08:42:36 I've been using `less` Jul 27 08:42:53 is `let` a C++ thing? Jul 27 08:42:59 #define let auto Jul 27 08:43:05 ah Jul 27 08:43:25 I do that because it fits the various uses of "auto" in C++17 much better than the word "auto" Jul 27 08:43:51 I'm thinking of having this program run in the background accepting instructions to change the values it's sending over a socket Jul 27 08:44:12 the dmx values you mean? Jul 27 08:44:14 and then having a second program send instructions based on user input Jul 27 08:44:17 yeah Jul 27 08:44:23 does that make sense? Jul 27 08:44:52 I mean, it's probably less effort to just mmap() the dmx buffer in whatever program is generating the dmx values Jul 27 08:45:40 that might make more sense... Jul 27 08:46:07 but maybe a socket is a better interface than weirdly mmapped memory Jul 27 08:46:16 I was still going to explain how to do the DT to make a separate /dev/uio/dmx-buffer to make sure the process that maps it doesn't get access to all of pruss Jul 27 08:46:23 I mean, that's your call Jul 27 08:46:33 oh yeah, how do I do that? Jul 27 08:46:43 (and what's a DT?) Jul 27 08:47:01 you could just expose a DBus interface to set DMX values, :D Jul 27 08:47:17 DT is Device Tree Jul 27 08:47:29 the thing that describes to the kernel what platform devices exist Jul 27 08:47:43 is it related to udev? Jul 27 08:47:47 I just learned what udev is Jul 27 08:48:30 udev is a userspace service that does userspace stuff based on information published by the kernel. DT is a data structure passed *to* the kernel by the bootloader Jul 27 08:48:52 ah Jul 27 08:49:12 you can view a filesystem representation of DT via /proc/device-tree Jul 27 08:49:35 in sysfs you'll also frequently see "of_node" symlinks that point to the DT node for a device Jul 27 08:50:22 (the of_ prefix refers to Open Firmware. DT was originally created as a way to serialize the Open Firmware device tree into a data structure which could then be used by the kernel) Jul 27 08:52:03 on most ARM-based embedded systems, the bootloader just loads a single .dtb file and passes its contents to the kernel. this dtb file is created by compiling a .dts file using the device tree compiler (dtc), which usually happens when you compile the kernel Jul 27 08:52:31 on beaglebones, u-boot has been enhanced to be able to apply "overlays" (loaded from .dtbo files) to the base dtb, allowing it to be modularized Jul 27 08:52:39 why are devices a tree? Jul 27 08:52:41 this is why you can e.g. disable hdmi video in /boot/uEnv.txt Jul 27 08:53:52 because frequently you access devices "through" another device. for example, i2c devices connected to some i2c bus are child-devices of the i2c bus device Jul 27 08:54:18 and most peripherals are children of the device that represents the SoC interconnect (&ocp) Jul 27 08:55:18 to create the /dev/uio/dmx-buffer we'll also need to create a tree structure... lemme write up what I mean Jul 27 08:56:05 by adding one of those overlays? Jul 27 08:57:19 replacing one, you're already using an overlay to enable uio-pruss Jul 27 09:04:24 can you check something for me on your beaglebone: Jul 27 09:04:25 grep SIMPLE_PM_BUS /boot/config-$(uname -r) Jul 27 09:05:58 =y Jul 27 09:06:02 good Jul 27 09:09:33 so, right now you're using the AM335-PRU-UIO-00A0 overlay, which declares something like this: https://pastebin.com/raw/X4CLbH7e Jul 27 09:10:39 you'd replace that by something like this: https://pastebin.com/raw/je5uPST5 Jul 27 09:11:29 it turns pruss itself into a simple-pm-bus devices, and moves the uio-pruss to be a child thereof Jul 27 09:11:36 to be able to create a second child for the dmx buffer Jul 27 09:12:09 I don't understand most of that Jul 27 09:12:13 they can't simply be direct children of &ocp, since there's shared power-management stuff associated with pruss Jul 27 09:12:43 the example overlay, I mean Jul 27 09:13:06 oh lol and I see a typo... "doisabled" is obviously "disabled" ... fortunately it's just in the comments Jul 27 09:13:19 yeah DT takes a bit of getting used to Jul 27 09:16:02 but if you grab https://github.com/mvduin/overlay-utils then save https://pastebin.com/raw/je5uPST5 into a file "my-uio.dtsi" and do "make my-uio.dtbo", copy the resulting file to /lib/firmware/, and change the uboot_overlay_pru variable in /boot/uEnv.txt to point to that instead of /lib/firmware/AM335X-PRU-UIO-00A0.dtbo, then you should have a new uio device for a dmx buffer (which I've put in pruss ... Jul 27 09:16:08 ...shared memory, i.e. offset 0x10000 in pruss Jul 27 09:16:45 I have some notes about device tree syntax here: https://pastebin.com/XC8vB33d Jul 27 09:19:13 wow, I'll look through that! Jul 27 09:23:01 what happens if I try to write to DRAM while the PRU is trying to read from it? Jul 27 09:23:43 one of the two will be stalled by one cycle (5ns)... most likely the access from the cortex-a8, I think the pru cores have a higher priority Jul 27 09:24:03 that's convenient Jul 27 09:41:23 there are actually negligibly-documented priority control registers in the pruss local interconnect... playing with them to figure out what they do is still on my to-do list Jul 27 22:35:57 I don't understand how the tree structure and bytes defined by a DT overlay correspond to devices Jul 27 22:40:38 are there specific properties and nodes I need to set up to tell the kernel how to use devices? Jul 27 23:02:10 yes Jul 27 23:03:43 how can I find out which ones? Jul 27 23:04:41 what device ? Jul 27 23:04:54 usually I just look in the root device tree source code Jul 27 23:04:59 you have everything you need Jul 27 23:05:39 zmatt was helping me set up a device that I can use to control just one part of the PRU's DRAM Jul 27 23:06:15 I don't understand what most of the properties or their values mean Jul 27 23:06:27 can you show that piece ? Jul 27 23:06:31 I can maybe explain the parts Jul 27 23:06:39 https://pastebin.com/raw/je5uPST5 Jul 27 23:06:48 ok Jul 27 23:06:55 ocp means on chip peripheral, starting from the beggining Jul 27 23:06:58 there are some comments, but I don't understand how they correspond to the non-comment lines Jul 27 23:07:14 that's the node that contains the PRU? Jul 27 23:07:22 yes apparently Jul 27 23:08:07 the "pruss:" part defines a global label for that node, right? Jul 27 23:08:29 why would I need a global label that isn't used later? Jul 27 23:09:30 my memory about DT is not extra fresh Jul 27 23:09:33 just try to remove it Jul 27 23:09:37 experimentation is the way to go Jul 27 23:09:48 okay! Jul 27 23:14:47 what does a line starting with '#' mean? Jul 27 23:15:48 it's just a special variable Jul 27 23:15:54 #address-cells Jul 27 23:15:57 oh Jul 27 23:15:58 as a whole Jul 27 23:16:08 the # is part of the name Jul 27 23:16:26 the # variables are present in many dt pieces Jul 28 02:09:39 mawk: actually I'm somewhat reasonably sure that originally &ocp referred to the Open Core Protocol connetion to the system interconnect, but since then people came up all with sorts of backronyms Jul 28 02:11:53 ksft: the pruss: label is just there in case some other overlay needs it... it was there in the main DT when the pruss declaration was still part of it, it is part of the standard overlay for uio-pruss, so I just kept it Jul 28 02:12:19 there is no strict "need" for it Jul 28 02:47:30 ah, I see **** ENDING LOGGING AT Sun Jul 28 02:59:57 2019