Open TomasRa1 opened 9 months ago
Ability to switch which PWM is being used will be part of #27, but it is just the framework at the moment
I decided to keep #27 to be the basic enable/disable for PWM. I'll start a new pull request to allow changing which pins are being used for PWM and I2C.
@TomasRa1 I've had some time to read through all the info you posted. I've ordered, what looks like, the same I2S board so I have a way to test. (https://www.amazon.com/gp/product/B08SLPHY2Z/)
I did find https://forums.raspberrypi.com/viewtopic.php?t=220082 mentioned being able to use i2s and hardware pwm at the same time by moving pwm to Pin 32 / GPIO 12, so I'm going to give that a try first. That would allow the hardware pwm to still be used, just on a different pin.
I saw your use of RPi.GPIO so I looked into it more as an option for software PWM. That which lead me to https://pythonhosted.org/RPIO/. RPIO can do PWM by using DMA, so it's the middle ground between hardware PWM and software PWM. Something I can look into, especially if the hardware pwm pin change doesn't work.
I've started work on being able to change hardware PWM pins. It's up as a draft PR #28
Thank you very much Nick! HiFiBerry DAC needs these Rpi GPIOs: +5V/pin2, GND/pin6, BCK/pin12, LCK/pin35, Din/pin40. There are GPIO pins 18, 19, 21. I would like to prefer configure any free pin for PWM, because it is universal at all cases. Pin 11 (Gpio17) is located next to GND pin and it is thanks this position shielded from other i2c pins, which we use for Transmitter module and at the same time pin11 is next to these i2c pins, we can easy use flat 6pin connector for RPi and Transmitter interconnection. I think it is favorable to use pin11 for PWM.
It is also possible to update PWM value dynamically in time, we do not need restart FPPD or any reboot for to change PWM value (the same as power of TX chip 8066). I changed Dynamic_RDS.php and settings.json source files (as I already described here above) for this dynamic set of PWM value. And also tested OK.
I've got the hardware PWM pin selection done in #28 Next, I'll follow your idea and make the PWM value dynamic so restarts are not needed. After that, I'll start looking into using RPIO so any gpio pin can be PWM.
@TomasRa1 I've merged #28, but it required an FPP change that has been merged, but only to master/fpp. I've guessing the next release will have it. Until then, the hardware pwm pin change won't work.
I'll start looking into using RPIO next!
I have been looking for a nice DAC that has RCA outputs. I found this (https://www.amazon.com/Decoder-Amplifier-PCM5102-PCM5102A-Headphone/dp/B0C7KQPR7S/ref=sr_1_50?crid=KTYBTOFN5CGZ&keywords=PCM5102&qid=1704083256&s=industrial&sprefix=pcm5102%2Cindustrial%2C104&sr=1-50) and just wondering if you think this would work also? It seems to have the same connections.
Yes, it is the same chip PCM5102A, it must also works.
I hope that connection could be:
BCK = BCK
DATA = DIN
LRCK = LCK
GND = GND
VCC = VIN
FLT=N = SCK jumper soldered (ICpin12=GND) FMT=I2S
Please, test it and inform us regarding result if my ideas above are correct. Thank you.
@TomasRa1 I've merged #28, but it required an FPP change that has been merged, but only to master/fpp. I've guessing the next release will have it. Until then, the hardware pwm pin change won't work.
I'll start looking into using RPIO next!
It will be nice to implement PWM via RPIO, thank you very much! https://pythonhosted.org/RPIO/
from RPIO import PWM
# Setup PWM and DMA channel 0
PWM.setup()
PWM.init_channel(0)
# Add some pulses to the subcycle
PWM.add_channel_pulse(0, 17, 0, 50)
PWM.add_channel_pulse(0, 17, 100, 50)
# Stop PWM for specific GPIO on channel 0
PWM.clear_channel_gpio(0, 17)
# Shutdown all PWM and DMA activity
PWM.cleanup()
The merge of #31 makes it so the dynamic changing of the pwm amp power works. I'm continuing work on RPIO
Draft pull request of work in progress is up #34
RPIO is pretty old and no longer maintained, so it doesn't have support already in place for the newer Pi's. I'm looking into options to update it or finding a similar PWM via DMA library. A key part is finding something that is light weight.
I dont know if it helps, but maybe look at WLED and what they are doing? It seems they have the ability to move pins around so they must be using something. Maybe it would work for PI. Again, I am no programmer, just tossing ideas out.
Should the DAC be able to work now without affecting this plugin? Because I have the DAC hooked up and it is working (outputs sound), but now I am seeing issues with this plugin. I believe PWM is not working as I can no longer adjust the power. I have the PWM set to "PIN 32 / GPIO 12". The only reason I am thinking this is because my range is no where near what it was before.
I'll check that pin's output and try to add in my DAC this weekend to test.
@chrkov I've not physically hooked up the DAC yet, but I did setup everything on the PI for it (confirmed that is show up with aplay -l). Using my logic analyzer, I can see PWM output on Pin 32. Something might change when I actually connect the DAC and play audio, so I'll check again once I'm to that point.
PWM via DMA Notes Seems that no single option would cover everything, but seems like bringing together parts of each might be an option.
https://github.com/jbentham/rpi
https://github.com/besp9510/dma_pwm
https://github.com/metachris/RPIO
https://sourceforge.net/projects/raspberry-gpio-python/
Is there any logs or anything I can do to help troubleshoot the issue? I am not sure if there is any feedback given when the change is made to see if its taken. I can see in the logs when I make a change to the power:
03:36:46 INFO Config {'DynRDSEnableRDS': '1', 'DynRDSPSUpdateRate': '2', 'DynRDSPSStyle': 'Merry|Christ-|-mas!', 'DynRDSRTUpdateRate': '6', 'DynRDSRTSize': '32', 'DynRDSRTStyle': 'Christmas on 124th Ave|{T}[ / {A}]|[Track {N} of {C}]|See you for the 2024 Show!', 'DynRDSPty': '22', 'DynRDSPICode': '3DC6', 'DynRDSTransmitter': 'QN8066', 'DynRDSFrequency': '88.9', 'DynRDSPreemphasis': '75us', 'DynRDSQN8066Gain': '0', 'DynRDSQN8066SoftClipping': '1', 'DynRDSQN8066AGC': '0', 'DynRDSQN8066ChipPower': '122', 'DynRDSQN8066PIHardwarePWM': '1', 'DynRDSQN8066AmpPower': '100', 'DynRDSStart': 'FPPDStart', 'DynRDSStop': 'Never', 'DynRDSCallbackLogLevel': 'INFO', 'DynRDSEngineLogLevel': 'INFO', 'DynRDSmpcEnable': '1', 'DynRDSAdvPISoftwareI2C': '1', 'DynRDSAdvPIPWMPin': '12,4', 'DynRDSQN8066DigitalGain': 0, 'DynRDSQN8066InputImpedance': 1, 'DynRDSQN8066BufferGain': 1}
Nick, please, try to use RPi.GPIO solution and adapt it, please. I tested it sucessfully. Yes, it is SW emulation, but we do not need extrem speed resp. PWM frequency 18kHz is low and RPi manage it without any problem or any overload. It is good to block PWM pin on the transmitter board by small ceramic capacitor 22n against GND. This capacitor round the edges of the pulses and remove noise from the PWM wire and capacitive coupling PWM signal to other wires. I also tested sucessfully.
Chrkov: (if I understand correctly) PWM signal is only transmited signal from RPi to transmitter (TX) board. On the TXboard is analog OP which convert digital PWM signal to analog level, which regulate voltage to PA driver. It is simple passive analog solution, not digital. Due to PWM signal cannot be validated by CPU as backward received data for secondary validation. We can only set PWM frequency and duty cycle and regarding duty cycle we can display percentual level of regulated voltage - eg. 100% = 10V and 10% = 1V, etc. We cannot validate how to data were set. We can only display actual set value of duty cycle. But you can connect SWR metter between RF output connector and antenna and you can see forward (and reflected) output power directly.
So two things. 1. Can I put a voltage meter on the PWM pin then and measure the voltage out to verify if its working then? If so, was your example about 1V = 10% and 10V = 100% just an example or what I should really see?
Is there a cheap SWR meter? I would only need it for this, so I dont want to spend a lot on it. Does something like this (https://www.amazon.com/Astatic-PDC1-100-Watt-Meter/dp/B004ULN610) do the trick for basic testing? It says for CB, but I know those frequencies are different than FM.
Is there any logs or anything I can do to help troubleshoot the issue? I am not sure if there is any feedback given when the change is made to see if its taken. I can see in the logs when I make a change to the power:....
@chrkov Can you run grep -i dt /boot/config.txt
? That will list the dtparam and dtoverlay lines. It's possible that something got messed up since the code to edit that file is not very fancy.
You can also see what the PWM settings are with
cat /sys/class/pwm/pwmchip0/pwm0/period
Should be 18300
cat /sys/class/pwm/pwmchip0/pwm0/duty_cycle
Varies with Amp Power setting
cat /sys/class/pwm/pwmchip0/pwm0/enable
Should be 1
Also, I just merged #34 which gets the other 2 hardware pwm pins working. You might give that a try.
Nick, please, try to use RPi.GPIO solution and adapt it, please. I tested it sucessfully. Yes, it is SW emulation, but we do not need extrem speed resp. PWM frequency 18kHz is low and RPi manage it without any problem or any overload. It is good to block PWM pin on the transmitter board by small ceramic capacitor 22n against GND. This capacitor round the edges of the pulses and remove noise from the PWM wire and capacitive coupling PWM signal to other wires. I also tested sucessfully.
@TomasRa1 I'll take a look at this route with software PWM as much as I don't like it :) Since you've had success with it, it does give me confidence that it is a reasonable option.
Here is the outputs of those commands. None of the cat commands found a file? Is there a typo there or is that my problem? If I do a 'ls' under /sys/class/pwm' I dont see any subdirs...
fpp@cmk-od-fpp01:~ $ grep -i dt /boot/config.txt
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1
dtparam=spi=on
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1
dtoverlay=pwm dtparam=i2s=on dtoverlay=hifiberry-dac dtparam=i2c_arm=on
fpp@cmk-od-fpp01:~ $ cat /sys/class/pwm/pwmchip0/pwm0/period cat: /sys/class/pwm/pwmchip0/pwm0/period: No such file or directory fpp@cmk-od-fpp01:~ $ cat /sys/class/pwm/pwmchip0/pwm0/duty_cycle cat: /sys/class/pwm/pwmchip0/pwm0/duty_cycle: No such file or directory fpp@cmk-od-fpp01:~ $ cat /sys/class/pwm/pwmchip0/pwm0/enable cat: /sys/class/pwm/pwmchip0/pwm0/enable: No such file or directory
@chrkov For the cat commands, that tells me the hardware pwm didn't get setup correctly for some reason. A few things in your config.txt that might be part of it:
dtoverlay=pwm
dtparam=i2c_arm=on
While neither are wrong, the plugin updates the pwm line with pin and func (otherwise it defaults to Pin 12 / GPIO 18). The i2c_arm=on is hardware i2c where the i2c-gpio is the software i2c. I'm surprised to see both.
If you haven't already, update the plugin to get the latest.
To see if we can get it out of this state using the plugin, on the Dynamic_RDS config page, change the PI PWM Pin to Pin 12 / GPIO 18, uncheck Enable Pi PWM, uncheck Use PI Software I2C. That should clean up things in the /boot/config.txt. You can check with the grep -i dt /boot/config.txt
to see the changes. Next, you can re-enable PWM, re-enable software I2C, and set your PWM pin again. Run the grep command again and you should see lines like:
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1
without an uncommented dtparm=i2c_arm=on
dtoverlay=pwm,pin=12,func=4
After that reboot and see if that clears things up.
For comparison, here's what the grep -i dt /boot/config.txt
looks like for me:
fpp@FPP-DevPi:~/media/plugins/Dynamic_RDS $ grep -i dt /boot/config.txt
#framebuffer_width=1280
#sdtv_mode=2
#dtparam=i2c_arm=on
dtparam=i2s=on
dtoverlay=hifiberry-dac
#dtparam=spi=on
#dtoverlay=gpio-ir,gpio_pin=17
#dtoverlay=gpio-ir-tx,gpio_pin=18
#dtparam=audio=on
dtoverlay=pwm,pin=18,func=2
#dtoverlay=vc4-kms-v3d
dtparam=spi=on
dtparam=i2c_arm=on,i2c_arm_baudrate=400000
#dtparam=audio=on
#dtoverlay=pwm,pin=13,func=4
dtoverlay=pi3-miniuart-bt
dtoverlay=dwc2
So I did the following. Change PWM pin to 12, disabled PWM and disabled Software I2C. Rebooted. Ran check on config.txt with output.
fpp@cmk-od-fpp01:~ $ grep -i dt /boot/config.txt
dtparam=i2c_arm=on
dtparam=spi=on dtparam=i2c_arm=on
dtparam=i2s=on dtparam=i2c_arm=on dtparam=i2s=on dtparam=i2s=on dtoverlay=hifiberry-dac dtparam=i2s=on
Not sure why I see so many dtparam=i2c=on now.
Go back in to config and reenable PWM, Software I2C and set pin to 32. Reboot.
Run check on config.txt and it is now:
fpp@cmk-od-fpp01:~ $ grep -i dt /boot/config.txt
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1
dtparam=spi=on
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1
dtparam=i2s=on
dtoverlay=i2c-gpio,i2c_gpio_sda=2,i2c_gpio_scl=3,i2c_gpio_delay_us=4,bus=1 dtparam=i2s=on dtparam=i2s=on dtoverlay=hifiberry-dac dtparam=i2s=on
and the Config page says this:
and still nothing under the directory /sys/class/pwm
I also did upgrade to 7.5. and after the upgrade the DAC was gone. I checked before I did anything and the /sys/class/pwm directory was populated and the cat commands all came back as you said. Then I ran the Enable_HiFiBerry.sh script and the /sys/class/pwm directory went blank again. I am starting to thing that script does something to cause me issues. Is that the script you guys are using to enable the DAC also?
@chrkov I'm still not sure what is happening that's causing the issue. The first config.txt output shows me that the i2c setting updated in the config.txt from software to hardware as expected. As expected, the pwm line was removed, but it should have uncommented #dtparam=audio=on as well, but that doesn't appear to be the case.
In the second config.txt output, again, it looks like the i2c settings worked as expected, but no pwm line appears. It should be right after the #dtparam=audio=on lines.
I'm not familiar with the Enable_HiFiBerry.sh script, but I'll take a look. I'm guessing it adds the dtparam=i2s=on and dtverlay=hifiberry-dac lines. I had just followed https://blog.himbeer.me/2018/12/27/how-to-connect-a-pcm5102-i2s-dac-to-your-raspberry-pi/ and manually updated the /boot/config.txt.
You can manually add the following to your /boot/config.txt to setup PWM on Pin 32 / GPIO 12:
dtoverlay=pwm,pin=12,func=4
I'd put it right after one of the #dtparam=audio=on
lines
ok. Pretty sure that using the Enable_HiFiBerry.sh script did something bad to my system. I have noticed several oddities since I did that (Like my UserCallbackHook.sh script no long runs either). I grabbed a new SD card and reinstalled a fresh copy of FPP 7.5 and installed everything and its working perfect (like before I added the DAC) but using your directions above for adding the DAC. I think we are all good now.
This morning, after rebooting my Pi, I noticed that pwm wasn't working. Looking into the syslog to see why, I discovered that there is a race condition in startup between the hardware pwm0 on pin 18 and i2s when both are enabled. While I know they both want pin 18, it seems like it is random who gets it. I'm not using the DAC yet, so that's why I still have pin 18 set. It should be easy enough to check for, so I'll add a warning about it.
@TomasRa1 I've got my first version of software PWM in #36 now. Once I split out the PWM functionality to a new class, it went pretty quick to get it added. More testing is needed to make sure it works well.
I've been looking at the software PWM output with my logic analyzer. Here's what I have observed so far - While I set the base frequency to 10kHz, I'm seeing something closer to ~4-6kHz. Trying an Amp Power of 30, which sets a 10% duty cycle, I'm seeing much higher (25-35%) on my analyzer. While I haven't try it on the transmitter yet, I expect it will increase the output power, but the control of it won't be as good as the hardware PWM (which runs at 54.6kHz).
I'll spend some more time to see if I can get this to be better.
I've merged #36 to the main branch, so you can update the plugin. To use the software PWM, enable PWM, then select a Software pin in the advanced options.
Testing out Pin 11 right now and everything seems to be working well.
I am guessing Duty Cycles are different?
@chrkov The frequency of the software PWM is an order of magnitude slower than hardware PWM (5 kHz vs 50 kHz). The duty cycle with software PWM is not as granular either, so you might find an Amp Power of 1 and an Amp Power of 30 have about the same effect on the transmitter.
I don't have enough electrical engineering knowledge to know how the slower PWM frequency impacts the amplification circuit on the transmitter board, but I'm glad to hear that it seems to do something :)
Hello Nick, thank you very much for your great work! Real measured frequency of PWM could be outside of audible frequencies, which is used for FM transmitting, which is up to 15kHz and also outside of all FM subcarrier frequencies: 19kHz-pilot stereo, 38kHz-L/R switching, 56-58kHz-RDS. I think that optimal real measured output PWM frequency, which cannot interfere in FM radio chain is around 18kHz, because audible frequencies around 19kHz are suppressed in stereocoder on transmitter side and also on FM receiver side. Frequency 5kHz could be audible as whistling. I recommend to set PWM frequency to output frequency around 18kHz eg. 17-18kHz. Thank you again for all!
@TomasRa1 I'll do some more testing and tweaking to see if I can get a higher frequency out of the software pwm. I might also see about making the software pwm period/frequency a configurable advanced option as well.
@TomasRa1 @chrkov I've spent sometime testing different things with Software PWM and the results are disappointing. For reference, this was all tested on a Raspberry Pi 3B+. The short version is that no matter what I've set, the actual PWM output is significantly different than expected and is effectively providing more power to the transmitter than desired. I'm not even factoring in the jitter and other inconsistencies in timing I saw. I tried to get the best, most consistent numbers, while testing.
Set Freq - What I used in the code to initialize RPi.GPIO Set Amp Power - From config screen T1 Duty Cycle - Measured the time of the high part of the pwm T2 Period - Measured from the start of high to the next start of high Calc Freq - Calculated the frequency from T2 Calc Amp Power - What the equivalent Amp Power setting would be based on the pwm measurements
As the pwm frequency goes up, the actual frequency measured gets further from expected. At 2000Hz, it's pretty close, but even 5000Hz is only managing 3000Hz and it continues to get worse from there.
Amp Power basically corresponds to the Duty Cycle, but you can see that at low amp power setting, the measured amp power (derived from the duty cycle) is much higher than it should be. At the higher frequencies, it is much worse, but even at 2000Hz it isn't great.
I'm going to look over the code in RPi.GPIO to see if anything looks odd, especially around the frequency.
I tested with set frequency to 18kHz (as I wrote in the code) and not registered inconsistency in power regulation. Maybe it was not perfect, but in real operation the regulation was consistent. When I will have a time I try to measure PWM signal with osciloscope. I understand that set frequency is different (lower with dependency on the frequency) than real transmitted PWM frequency. I used blocking capacitor 22n connected from PWM pin to GND on the transmitter board and check on osciloscope that edges of pulses are rounded. I also check that PWM frequency from original china's CPU controller was around 54kHz. I will inform later.
On https://www.aliexpress.com/item/1005005393398013.html is possible to buy very cheap but with relatively good audio quality DAC for Rpi with IC PCM5102A.
It works nicely as good quality audio driver for FM transmitter as I tested.
For Rpi connection it needs these Rpi GPIOs: +5V/pin2, GND/pin6, BCK/pin12, LCK/pin35, Din/pin40
You can see on picture mutual connection and also 4 PCB jumpers, which must be soldered as on this picture:
For to use this or similar Rpi HifiBerry DAC or also for to use Rpi built-in PCM DAC we need reconnect Dynamic_RDS PWM output from pin32 (GPIO12) PWM0 to any other free pin, because built-in Rpi audio or external HifiBerry DAC needs this pin PWM0.
For more detailed informations regarding Rpi implementation of this HifiBerry DAC module, please visit eg. https://blog.himbeer.me/2018/12/27/how-to-connect-a-pcm5102-i2s-dac-to-your-raspberry-pi/.
I decided to use RPi pin11 (GPIO17) for PWM output.
It needs to modify "Dynamic_RDS_Engine.py".
@atexit.register def cleanup(): try: logging.debug('Cleaning up fifo') os.unlink(fifo_path) except: pass logging.info('Exiting')
===============
Basic I2C Class