i2c oled splash screen

hi folks,

I am noob please help!, i have a ss1309 oled display running with luma.oled library. currently working fine when linux is up and running. it takes around a minute for system to boot and display to show splash screen(crontab).
What i want is when power is connected it should display loading or text( or ~4-5 sec later) when the linux is booting. I have seached some methords but not able to implement them.
Things i have searched:- PRU(learning curve :), CRONTAB(takes so much time), U-Boot(didnt understand), BITBANG(tried only on linux)
Are there any tried and tested way that are easy to run splash screen in beaglebone

Thanks Folks

In my opinion, there’s only really one option for you: u-boot.

Unless ofc. you want to stick it on a separate micro, say a PI Pico or something,
and let that drive the display, while emulating a comms device for Linux to
bridge with, once it’s alive and kicking.

thanks for the reply,
although there i cannot add another uc, i have seen that bbb have inbuilt dual core microcontroller (for fast implementation of baremetal). I dont have any lead on how to implement i2c and oled with it, or i havent tried running it before boot time(only thing i tried is running user led example). I dont even know if it is possible to access i2c bus with pru.

Anything you can access from the main CPU, you can access from the PRUs via OCP.

The question though, becomes how to get any kind of code loaded into their execution space.
I’m thinking via u-boot, but then the whole PRU exercise becomes rather redundant.

thanks for the reply,
i am willing to try u-boot method can you explain how can i execute code from uboot without flashing a new firmware. while searching i found that we can flash pru that executes code when power is on(is it true?), so that doesnt require ARM to be running!

also i need some example codes that can help flashing pru…

although thanks for your help

Well, since u-boot is just a collection of code, freely available,
there’s nothing stopping you from expanding on what’s already there.

I have no idea about autoloading code to the PRUs at power-on.
For that, you would have to consult with TI, I think.

@jkridner, any ideas?

I believe that once your PRU code is compiled and moved into the correct directory it is persistent there. Then, it is a matter of starting the PRU which I think can probably be done at boot from the ARM side of the BeagleBone. I don’t have a system available right now but I believe the directory /dev/remoteproc/pruss-core# where # is the number of the PRU you want to start or stop is where you enable or disable the PRU. Enabling runs the code you’ve already loaded.

I spent a lot of time learning, crashing, screaming and crying with the PRUs on the BeagleBone Black but at the end of the day, we were pleased with how well it ran our prototype system. Here are some notes I made at the time and may have already shared. But for convenience, here they are again. This information is for Linux Buster distribution with kernel 4.19.x. An oldie but a usually goodie.

I have recently starting using the PRUs with C and began to learn this from scratch. I want to thank everyone on this group who has helped me along the way.

For the next person coming along trying to learn this, I want to share some things that may be helpful. I was an old dog relearning tricks and learning new tricks when I started this journey. It was tough and frustrating at times so hopefully this might help someone learn faster.

1. Working with the PRUs is not easy.  Although it isn't easy, once you get the hang of it you'll be impressed with the expanded functionality and flexibility of this system on a chip (SOC) that you gain.
2. If you are rusty on using 'C' or just sloppy with memory allocation, pointers and addresses, spend some time getting back up to speed on these concepts.  This will save you hours in the long run.
3. If your mental conversion from decimal to hex to binary gets foggy sometimes, use Excel and create a simple tool to help you convert one to the other.  It has built in DEC2HEX, HEX2BIN, BIN2HEX, etc. functions.  
4. I did not use CCS or a debug probe.  They probably make some things easier but I can't say.  
5. Get used to not being able to output anything from the PRU code directly to a terminal unless you hook up a separate terminal or other output device.  The PRUs don't really run an OS like Linux so they don't have stdout type functions to use.
6. Get the PRU software development package from TI and download it to your Beagle using git.
7. If you don't need them, disable audio and video support in /boot/uEnv.txt
8. Spend some time studying TI's Sitarra Technical Reference Manual (TRM) for the am335x series.  I mean really study it.  Get familiar with the architecture of the chip and all the on-chip peripherals.  In the interest of time, deep dive only on the ones you'll be using.
9. Note that floating point operations are not supported in PRU hardware and are discouraged by TI.  If you must use them, know that they will use a lot of code and cycles and you may not have enough space to load your program.  So use them sparingly.
10. Get familiar with the utilities available with the TI Assembly Language tools. In particular, ofdpru will breakdown your object file and help you know how much memory you'll be using and where.
11. Spend time going through Mark Yoder's PRU Cookbook.  Do the examples.
12. Spend time going through TI's Hands On Labs.  Although currently they are aimed at running on a Linux-based development platform, it's not required.  You can still learn from the hands on labs even if you are running a Windows machine as your platform.  Also, although TI assumes you are using Code Compiler Studio (CCS), it is not required.  I used a combination of the Cloud9 IDE that ships with the BB for development of my code for both the host and PRU side.  It lets me run code on the host side in the IDE.   I then use a PUTTY session to make and load my PRU code.   I suppose I could use a terminal session in Cloud9 to do this but using the PuTTY session is a nice way to keep the two types of code differentiated in my mind.
13. Understand the toolchain you are using and what it is doing but you don't have to initially understand every intricacy of the Makefile.  
14. Get really comfortable with the registers that you'll use.  Be aware that sometimes TI splits the configuration value  across a nibble.  An example is the Touch Screen Controller's four bits to set the analog channel input for a step.  It uses bits 19-22.  19 is the MSB of the fifth nibble.  Bits 20,21 and 22 are in the next nibble.  So to configure to use analog input 5, the hex value for those two nibbles must be 28.  
15. Specifically, study pin muxing.  It helps to understand why it is necessary.
16. Recognize just how small 8k of RAM is really.  Each PRU has only 8k of RAM for the firmware you download and your data.  This means you'll really need to pay attention to writing tight, efficient code.  If you run out of memory to load your program, first eliminate all floating point operations that you can and then begin to refine your code.
17. Study remoteproc thoroughly and get to know how it works like the back of your hand.  Basically, it is bi-directional i/o between the main processor running under Linux and the PRUs based on a concept of virtual i/o (aka virtio).  Once this sunk in for me, it became easier to use.
18. Make sure when you compile the firmware that you're using the right make file. Out of the box, Cloud9 will try to use gcc to compile and it won't recognize some of the C extensions TI has built into the PRU's compiler.   For this reason, I compile my PRU code from a terminal session with PUTTY.  There's probably a way to write a make file so this would work in Cloud9 but I didn't take the time to figure this out (yet).
19. When you are compiling your firmware with the make file, make sure to use TARGET=yourfilename or else you'll get errors because the make file is looking for the target.  If you don't you'll get errors around problems with header files, etc. that don't make sense and it could waste a lot of time.   Believe me, it is easy to forget this sometimes.
20. When learning remoteproc and RPMSG, I recommend starting with a very simple "round trip" message.  Send something like "Hi" to the PRU and have it send "Hi Back" and display it from the host program.
21. Whatever you have your PRU doing, when it is done, make sure to stop sending messages through RPMSG and stop all peripherals, otherwise you may just crash the whole SOC.

Firmware goes in /lib/firmware
Programs that compile new firmware must have access to copy the new file into this directory so if a Makefile is trying to update this, it must be run with privileges that allow writing to /lib/firmware

PRU0 sysfs files are in /sys/class/remoteproc/remoteproc0
PRU1 sysfs files are in /sys/class/remoteproc/remoteproc1
File firmware holds the name of the firmware file that will be loaded
It is loaded when the PRU is started. It has to be stopped then started again to load new firmware.

The registers _R30 and _R31 are used in a lot of the example code on-line and are confusing intially. Section 5.7.2 of the
PRU Optimizing C/C++ Compiler, v2.2, User’s Guide explains them.

My setup:
Windows 10 as my development station, using Chrome as my browser
Cloud9 as the IDE just as it ships with the Beaglebone Black
PUTTY as my terminal

Things to watch for when things aren’t going right.
Did you compile your PRU code with TARGET=yourfilename on the command line?
Have you used up all your memory?
Is the PRU starting when your firmware starts? Use dmesg -HW to watch what the Linux side is doing.

1 Like

First, Thanks for the given roadmap. It will be very helpful.
i have tried running cloud9 and PRUcookbook examples(blink userled1,2) they seems to be working fine. but when i try to compile my own it throws dependency errors.
i can confirm that path for pru firmware is
/sys/devices/platform/ocp/4a326004.pruss-soc bus/4a300000.pruss/4a334000.pru/remoteproc/remoteproc1
(correct me if im wrong)

Cloud9 is currently disabled in my case (something package disabled), so im running it while compiling by gcc and Makefiles. i havent tried putting any firmware init(will try and update)

is there any example that mimics the functionality for i2cdetect to check i2c device like it shows 3c when i put i2cdetect 1 =>> 3c

Although thanks for everyones reply

sir may i ask what dtbo you are using??

When you mention that Cloud9 is disabled, I am suspicious that you are running Bullseye.
I don’t (yet) have experience with the PRU on Bullseye. I have not been able to compile anything on it yet because Visual Code (the Cloud9 replacement) wants gdb installed and I have not been able to get that done yet. To be fair, I have not tried very much.

@m0nk What specific dtbo are you referring to?

If you are asking about the distribution my information is based on, here’s the information that might help.

eeprom:[A335BNLT00C04417BBBK1847]
model:[TI_AM335x_BeagleBone_Black]
dogtag:[BeagleBoard.org Debian Buster IoT Image 2020-04-06]
bootloader:[microSD-(push-button)]:[/dev/mmcblk0]:[U-Boot 2019.04-00002-g07d5700e21]:[location: dd MBR]
bootloader:[eMMC-(default)]:[/dev/mmcblk1]:[U-Boot 2018.03-00002-gac9cce7c6a]:[location: dd MBR]
UBOOT: Booted Device-Tree:[am335x-boneblack-uboot-univ.dts]
UBOOT: Loaded Overlay:[AM335X-PRU-RPROC-4-19-TI-00A0]
UBOOT: Loaded Overlay:[BB-ADC-00A0]
UBOOT: Loaded Overlay:[BB-BONE-eMMC1-01-00A0]
UBOOT: Loaded Overlay:[BB-I2C2-RTC-DS3231]
UBOOT: Loaded Overlay:[BB-W1-P9.12-00A2]
kernel:[4.19.94-ti-r61]
nodejs:[v10.15.2]
/boot/uEnv.txt Settings:
uboot_overlay_options:[enable_uboot_overlays=1]
uboot_overlay_options:[uboot_overlay_addr4=/lib/firmware/BB-W1-P9.12-00A0.dtbo]
uboot_overlay_options:[disable_uboot_overlay_video=1]
uboot_overlay_options:[disable_uboot_overlay_audio=1]
uboot_overlay_options:[uboot_overlay_pru=/lib/firmware/AM335X-PRU-RPROC-4-19-TI-00A0.dtbo]
uboot_overlay_options:[enable_uboot_cape_universal=1]
uboot_overlay_options:[dtb_overlay=/lib/firmware/BB-I2C2-RTC-DS3231.dtbo]
pkg check: to individually upgrade run: [sudo apt install --only-upgrade <pkg>]
pkg:[bb-cape-overlays]:[4.14.20210401.0-0~buster+20210401]
pkg:[bb-wl18xx-firmware]:[1.20200322.0-0rcnee0~buster+20200322]
pkg:[kmod]:[26-1]
pkg:[librobotcontrol]:[1.0.4-git20190227.1-0rcnee0~buster+20190327]
pkg:[firmware-ti-connectivity]:[20190717-2rcnee1~buster+20200305]
groups:[debian : debian adm kmem dialout cdrom floppy audio dip video plugdev users systemd-journal bluetooth netdev i2c gpio pwm eqep remoteproc admin spi iio docker tisdk weston-launch xenomai cloud9ide]
cmdline:[console=ttyO0,115200n8 bone_capemgr.uboot_capemgr_enabled=1 root=/dev/mmcblk0p1 ro rootfstype=ext4 rootwait coherent_pool=1M net.ifnames=0 lpj=1990656 rng_core.default_quality=100 quiet]
dmesg | grep remote
[   70.424168] remoteproc remoteproc0: wkup_m3 is available
[   70.537289] remoteproc remoteproc0: powering up wkup_m3
[   70.537322] remoteproc remoteproc0: Booting fw image am335x-pm-firmware.elf, size 217148
[   70.537592] remoteproc remoteproc0: remote processor wkup_m3 is now up
[   72.807404] remoteproc remoteproc1: 4a334000.pru is available
[   72.825531] remoteproc remoteproc2: 4a338000.pru is available
dmesg | grep pru
[   72.807404] remoteproc remoteproc1: 4a334000.pru is available
[   72.811832] pru-rproc 4a334000.pru: PRU rproc node pru@4a334000 probed successfully
[   72.825531] remoteproc remoteproc2: 4a338000.pru is available
[   72.825738] pru-rproc 4a338000.pru: PRU rproc node pru@4a338000 probed successfully
dmesg | grep pinctrl-single
[    0.951001] pinctrl-single 44e10800.pinmux: 142 pins, size 568
dmesg | grep gpio-of-helper
[    0.964886] gpio-of-helper ocp:cape-universal: ready
lsusb
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

What else is on your I2C bus? Is there something there that could be replaced with something more useful?

I’m facing the same dilemma for my LED light controllers and have found the best solution for me was to replace a few components with a small MCU that can startup the OLED on boot before linux takes it over. In my case, every board has a small EEPROM on it. Most also have additional A2D chips on the i2c bus (which are expensive). I’m replacing those with an MSPM0L1306TRGE which can emulate the EEPROM as well as an 8 channel A2D chip. I’ve programmed it so at power on, it sticks my logo on the OLED along with a quick message and then goes into its emulation code. This woks quite well. The Image stays on the OLED until the Linux process gets started at which point it takes overs.

In the end, it’s costing me about an extra 40cents on boards that don’t require additional A2D channels (difference in cost between eeprom and MSPM0L1306TRGE), but on boards that require additional channels, it’s saving me quite a bit of money.

You can see the source for the OLED init at:
mspm0-adc-eeprom/source/board/system.c at main · KulpLights/mspm0-adc-eeprom · GitHub
Since it’s just showing a static image, the bytes for that are static in the code. Very simple.

Very much in line with my original suggestion, although I never encountered
anything like this. Makes me think of the ATTiny family; very cool find there Daniel!

I didn’t actually “find” it. It’s how the PocketBeagle2 is handling the eeprom and A2D stuff on there and the base code in the git repo above is from the PocketBeagle2 code. Since it seems to be working OK for the PocketBeagle2, I figured it was worth investigating a bit more to see what else it can be useful for.

1 Like

Thanks for the reply, Using MSPM0L1306TRGE would be a great solution.

Rather i will be focusing more on PRU cz that’s already there(No offense), i would like to learn more about MSPM0L1306TRGE and PRU

Currently I am testing out PRUcookbook and Ti pru compiler which is headache it works but…:sweat_smile:
If I can get any example for accessing i2c or maybe a bit bang approach it’ll get more clear

Everyone Again thank for the Reply and directions for EEPROM, I will work on that in future.

It really depends on how far after “power on” do you want something displayed. Using an MCU of some sort allows it to be almost instant after power on (well under a second). The next option would be commands compiled into a custom u-boot which would likely be in the 1-3 second range. Something running from Linux kernel driver of some sort could likely be around the 3-6 second range. Anything other than that would likely be after about 8 or 9 seconds, maybe more. On my PocketBeagle2, the PRU’s are not available until about 7.5 seconds after the kernel is loaded/started which is a couple seconds after power on (due to u-boot).

That makes things more clear
so using PRU is still an overkill in my case that i dont even need instant power up, using U-boot will work fine in my case, i dont need instant power up. If it can run under ~5 sec or something it will work fine… i will be looking forward for U-boot (along with PRU as a challenge)
does anyone have guide any guide for U-boot that works with i2c devices

Anyways thanks for reply

I’m pretty sure that Google have plenty of guides, should you care to go looking.

I can’t imagine you being the first person ever to want to talk to some device via I2C.