Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hardware PMW function not working on Pi4B revision 1.4 #517

Open
joan2937 opened this issue Feb 9, 2022 · 63 comments
Open

Hardware PMW function not working on Pi4B revision 1.4 #517

joan2937 opened this issue Feb 9, 2022 · 63 comments

Comments

@joan2937
Copy link
Owner

joan2937 commented Feb 9, 2022

From https://forums.raspberrypi.com/viewtopic.php?t=329394

My team has built a custom hat which we use for controlling LEDs and Fans. This hat uses hardware PWM for controlling the fans. We've just tested it on a Raspberry Pi Model 4B rev 1.4 for the first time, and it looks like hardware PWM is no longer working. The hat is working fine on both Raspberry Pi model 3B+ and Raspberry Pi model 4B rev 1.2. We're curious if more people are running into similar issues?

We use Pigpio V79, and have tried this on three brand new Raspberry Pi Model 4B rev 1.4s, straight out of the box. All have the same issue. We've measured the PWM signal on GPIO12 (pin 32) using an oscilloscope. With the Rev 1.4 Pis, we get no signal. On the Rev 1.2 Pi or RPi3b+ we do measure the expected PWM signal.

Not sure how we can action this. I don't have a Pi4B revision 1.4 board and I guess that will be needed to identify the problem and fix.

@guymcswain
Copy link
Collaborator

Right, mine are revision 1.1

Oddly, one of the first searches I hit on rev 1.4 turned up an article about the changes having something to do with the USB-C interface confusing the root hub that it was an audio device. Perhaps we should ask the OP of they can try a generic/dumb USB-C cable (as opposed to the electronically marked or e-marked USB-C cable variety).

@martijnt
Copy link

martijnt commented Feb 10, 2022

OP here. I ran the v79 as requested by Joan, with all tests passing except for one in x_pigs (ERROR: No more CBs for waveform). Full logs here: pigpio-v79-pi4b-rev14-tests.txt

The cable we use is as dumb as it gets: a USB-C cable with only the +5V and GND wires connected to a dedicated 5V, 10A PSU (Mean Well MPM-65-5ST). We never had any power/throttling issues with this one.

We may be able to help with testing. We have a single rev 1.1, and a bunch of rev 1.2 and rev 1.4 boards, as well as CM4s + IO board. Let me know if there's anything you want us to check.

The board I used for testing has 2711ZPKFSB06C0T type indicator on the CPU cover. From Googling this seems to indicate a C0 stepping.

@joan2937
Copy link
Owner Author

joan2937 commented Feb 10, 2022

Stranger and stranger. The default tests use the PCM peripheral to pace DMA for GPIO sampling but will use the PWM peripheral for waves. So the PWM peripheral is working to an extent.

Could you possibly do another test as follows.

sudo killall pigpiod # make sure daemon stopped

sudo pigpiod -t0 # start the daemon with the PWM clock

./x_pigs

@martijnt
Copy link

Sure. Same error (ERROR: No more CBs for waveform)

Full results: pigpio-v79-pi4b-rev14-tests-v2.txt

@joan2937
Copy link
Owner Author

Interesting. Be patient for a quarter hour or so. I have another test in mind.

@joan2937
Copy link
Owner Author

Could you run the following Python with the normal daemon.

sudo killall pigpiod
sudo pigpiod
python3 test_hp.py
import pigpio
import time

G=12
TEST_TIME=5

pi = pigpio.pi()

if not pi.connected:
   exit()

cb = pi.callback(G)

for freq in [1, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000]:
   pi.hardware_PWM(G, freq, 500000)
   cb.reset_tally()
   time.sleep(TEST_TIME)
   print(freq, cb.tally()/TEST_TIME)

pi.stop()

@martijnt
Copy link

Sure, results here:

pi@pi-rev14:~/pigpio-79 $ sudo killall pigpiod
pi@pi-rev14:~/pigpio-79 $ sudo pigpiod
pi@pi-rev14:~/pigpio-79 $ python3 test_hp.py
1 0.8
10 8.4
20 19.8
50 49.8
100 100.0
200 200.0
500 500.4
1000 1000.0
2000 2001.8
5000 5005.0
10000 10010.0
20000 29.4
50000 49149.0

@martijnt
Copy link

The results for the 20k freq look strange. Ran the test again, same results:

pi@pi-rev14:~/pigpio-79 $ python3 test_hp.py
1 1.2
10 8.2
20 19.8
50 49.8
100 99.8
200 200.2
500 500.6
1000 1001.0
2000 2002.6
5000 5004.6
10000 10010.8
20000 26.0
50000 49380.8

Will try these on a rev12 board as well and report back

@joan2937
Copy link
Owner Author

Odder and odder. That looks okay apart from 20 kHz which seems to be wrong.

Could you try with GPIO 13 (rather than 12).

@martijnt
Copy link

Rev 12 results (still with GPIO 12):

1 1.2
10 8.2
20 19.8
50 49.8
100 100.0
200 200.0
500 499.8
1000 1001.0
2000 2000.8
5000 5004.6
10000 10009.0
20000 19909.8
50000 49767.8

Will try with GPIO 13 in a minute on both revisions

@martijnt
Copy link

GPIO 13 looks ok on both rev 1.2 and rev 1.4:

pi@pi-rev14:~/pigpio-79 $ python3 test_hp_gpio13.py
1 1.2
10 8.2
20 19.8
50 49.8
100 100.0
200 200.2
500 500.8
1000 999.8
2000 2000.0
5000 5004.4
10000 10009.6
20000 19875.8
50000 33584.2

pi@pi-rev12:~ $ python3 test_hp_gpio13.py
1 1.2
10 8.2
20 19.8
50 49.8
100 100.0
200 200.0
500 500.0
1000 1000.0
2000 2001.8
5000 5004.4
10000 9999.4
20000 19967.4
50000 49777.0

@martijnt
Copy link

Ran the tests on a rev 1.1 as well, with similar results as the rev 1.2 (both GPIO 12 and 13 work as expected)

@joan2937
Copy link
Owner Author

Odd and odder. For your use could you use GPIO13 or GPIO19 rather than GPIO12? Might be a temporary fix.

@martijnt
Copy link

I'm discussing the use of GPIO13 with my team. Meanwhile I'm trying to pinpoint the starting/end frequencies of this strange behaviour. I'm still narrowing it down, but it looks like it's not just 20Khz, more like 11Khz-45Khz.

@martijnt
Copy link

It could perhaps be related to audio, looking at these frequencies?

@joan2937
Copy link
Owner Author

When you do the tests do you use the same SD card in each Pi and do they have the same peripherals connected?

We have had odd results before but never managed to identify a reason or pattern.

@martijnt
Copy link

On the rev11 and rev12 Pi's I used an existing os installation, on both devices with different peripherals connected. On the rev14 Pi I used in the above test I've disconnected all peripherals before testing, except for a Raspberry pi 7" touchscreen and ethernet cable.

@martijnt
Copy link

Regarding the start / end frequencies:

pi@pi-rev14:~/pigpio-79 $ python3 test_hp_11khz.py
11300 11308.8
11305 11305.6
11310 11322.6
11315 11317.8
11320 11321.8
11325 11324.2
11330 11340.2
11335 11344.4
11340 11341.4
11345 11346.4
11350 11360.6
11355 11365.0
11360 6913.8
11365 6901.4
11370 6864.4
11375 5866.6
11380 6777.6
11385 7352.6
11390 8480.4
11395 8154.2
11400 46.0
11405 40.4
11410 31.6
11415 38.0
11420 46.6
11425 33.8


pi@pi-rev14:~/pigpio-79 $ python3 test_hp_45khz.py
45700 8.0
45705 3.0
45710 1.2
45715 3.8
45720 3.4
45725 4.0
45730 3.8
45735 1.6
45740 1.4
45745 4.6
45750 2.6
45755 2.0
45760 2.2
45765 2.6
45770 222.4
45775 31.8
45780 45705.8
45785 45826.8
45790 45723.2
45795 45699.8

@joan2937
Copy link
Owner Author

Thanks for that. Does seem suspiciously like audio. Guy and myself will have to give this some thought. We probably do need input from the Foundation unless we find some queer bug in our code.

@martijnt
Copy link

I'll run a few more tests to try to figure out which models (Model 4B & CM4) & OS combinations are affected. And ask if we can get some assistance from the Foundation for this issue. It looks like we have to create and produce a revision of our pcb to use GPIO 13, which would delay things on our end quite a bit. A workaround or fix would be most helpful. I'll also have a look if disabling audio will have any effect.

@martijnt
Copy link

And thanks for the support so far, Joan & Guy! Much appreciated!

@guymcswain
Copy link
Collaborator

ERROR: No more CBs for waveform

This is an expected, good, result from the test. I was lazy and never went back in the code to suppress it. Please ignore.

On the rev14 Pi I used in the above test I've disconnected all peripherals before testing, except for a Raspberry pi 7" touchscreen

I believe we have seen HDMI connections turn audio on in some configurations and cause conflict with pigpio. Could you run the rev 1.4 units headless just be verify this is not a factor?

@martijnt
Copy link

I've disconnected the DSI cable so the rev 1.4 test pi is now fully headless (with both Wifi & ethernet connected). The results are slightly different, now also giving problems at 10khz:

python3 test_hp.py
1 1.2
10 8.2
20 19.8
50 49.8
100 100.0
200 200.0
500 500.8
1000 1000.4
2000 2002.6
5000 4662.8
10000 13.6
20000 301.6
50000 48260.8

@guymcswain
Copy link
Collaborator

The board I used for testing has 2711ZPKFSB06C0T type indicator on the CPU cover. From Googling this seems to indicate a C0 stepping.

Note to ourselves: C0 has changes allowing DMA to access greater memory ranges. Hopefully firmware APIs did not change.

@guymcswain
Copy link
Collaborator

Ran above test_hp.py on pi400 (presumably uses C0 stepping, I haven't looked inside):
1 6.8
10 8.2
20 19.8
50 49.8
100 99.8
200 200.2
500 500.2
1000 1000.8
2000 2001.8
5000 5000.0
10000 3874.2
20000 23.4
50000 49745.0

@martijnt
Copy link

martijnt commented Feb 10, 2022

I've tested the issue with the Rev 1.4 Pi on all four latest OS builds (32/64-bit, Buster/Bullseye) using a slightly modified test_hp.py script. Same results, with varying frequency ranges that show the anomaly. I will check on the CM4 next.

Logs:
4b-rev14-buster32.log
4b-rev14-buster64.log
4b-rev14-bullseye32.log
4b-rev14-bullseye64.log

Note that hardware is reported as BCM2835 in the 64-bit builds

test_hp.py modified:

import pigpio
import time

G=12
TEST_TIME=5

pi = pigpio.pi()

if not pi.connected:
   exit()

cb = pi.callback(G)

def test(freq):
   pi.hardware_PWM(G, freq, 500000)
   cb.reset_tally()
   time.sleep(TEST_TIME)
   print(freq, cb.tally()/TEST_TIME)

print("Basic test:")
for freq in [1, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000]:
   test(freq)

print("\nFinding start:")
for freq in range(5000, 12000, 200):
   test(freq)

print("\nFinding end:")
for freq in range(43000, 48000, 200):
   test(freq)


pi.stop()

@guymcswain
Copy link
Collaborator

Thank you @martijnt , but I think it is pointing to pigpio on C0 step.

@guymcswain
Copy link
Collaborator

@joan2937 , please checkout this post from raspberrypi.stackexchange.com

To fix their u-boot issue, they had to change the virtual address of the XHCI PCI device! (see link to patch).

@martijnt
Copy link

The CM4 rev 1.0 has the issue too. This one also has a C0 stepping (same type number on the SOC).

@martijnt
Copy link

Unfortunately, I was a bit too quick to say GPIO13 is ok. I was focusing on the 20Khz counter, but overlooked 50Khz. If you look at the results for the test with GPIO13 on the rev14 above, you'll notice 50Khz is off as well (the counter is at 33k). I've repeated this test a couple of times this morning, and getting similar results (counter at 5854 in one test, 7691 in another).

I've run the test in the range our fans support [20khz-28khz], and it starts breaking down at around 23Khz:

$ python3 test_hp_gpio13_fan_range.py
20000 19991.6
20200 20209.2
20400 20264.8
20600 20678.4
20800 20906.8
21000 20971.6
21200 21059.2
21400 21606.8
21600 21561.0
21800 21798.4
22000 22000.8
22200 22107.2
22400 22465.2
22600 22813.6
22800 22814.2
23000 5767.0
23200 5953.0
23400 5375.4
23600 6139.0
23800 5222.6
24000 6147.0
24200 5932.2
24400 6838.4
24600 4942.0
24800 5524.4
25000 5293.8
25200 5472.6
25400 6258.0
25600 5639.8
25800 6061.0
26000 6405.4
26200 5974.6
26400 6167.2
26600 6220.2
26800 5827.0
27000 6405.6
27200 6070.4
27400 5730.8
27600 6601.8
27800 6253.4

@guymcswain
Copy link
Collaborator

guymcswain commented Feb 12, 2022

pigs hp 12 10000 500000 on o'scope shows a stable 10KHz 50% dutycycle for about 1 sec then becomes erratic - the scope is unable to sync to the waveform.

Next, I noticed that when switching between windows - terminal (showing pigs) and a browser - the waveform momentarily becomes stable then erratic again.

[EDIT] I'm using a Pi400. I've disconnected the monitor, rebooted and then ssh'ed in from a remote pc. Now my scope never syncs to the 10KHz waveform. 1KHz, however, is stable. So, I believe this test is validating what test_hp.py indicated - for a specific range of frequencies, the pwm in not functioning correctly.

@joan2937
Copy link
Owner Author

joan2937 commented Feb 12, 2022

I am using the following rather messy code (a merge of minimal gpio access and the hardware PWM code).

The oddity boundaries seem to be associated with range and/or dutycycle (as set in the PWM hardware) being powers of 2.
E.g. look at the break down between these values on a scope (or piscope).

$ sudo ./hwpwm 45780 12 500000
2711 = 1, peri base = fe000000, rev = 3130(12592)
gpio=12 frequency=45780 dutycycle=500000
ctl=40 div=41 src=6 /I=2 /f=0 M=3
range=8191 dc=4095

$ sudo ./hwpwm 45779 12 500000
2711 = 1, peri base = fe000000, rev = 3130(12592)
gpio=12 frequency=45779 dutycycle=500000
ctl=40 div=41 src=6 /I=2 /f=0 M=3
range=8192 dc=4096

Early days, but I'm sure there is a pattern. Getting more convinced the hardware is broken.

/*
   hwpwm.c
   2022-02-11
   Public Domain
*/

/*
   gcc -o hwpwm hwpwm.c
   sudo ./hwpwm
*/

#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>

#define BCM_PASSWD  (0x5A<<24)

#define CLK_CTL_MASH(x)((x)<<9)
#define CLK_CTL_BUSY    (1 <<7)
#define CLK_CTL_KILL    (1 <<5)
#define CLK_CTL_ENAB    (1 <<4)
#define CLK_CTL_SRC(x) ((x)<<0)

#define CLK_SRCS 2

#define CLK_CTL_SRC_OSC  1
#define CLK_CTL_SRC_PLLD 6

#define CLK_OSC_FREQ        19200000
#define CLK_OSC_FREQ_2711   54000000
#define CLK_PLLD_FREQ      500000000
#define CLK_PLLD_FREQ_2711 750000000

#define CLK_DIV_DIVI(x) ((x)<<12)
#define CLK_DIV_DIVF(x) ((x)<< 0)

#define CLK_GP0_CTL 28
#define CLK_GP0_DIV 29
#define CLK_GP1_CTL 30
#define CLK_GP1_DIV 31
#define CLK_GP2_CTL 32
#define CLK_GP2_DIV 33

#define CLK_PCMCTL 38
#define CLK_PCMDIV 39

#define CLK_PWMCTL 40
#define CLK_PWMDIV 41

#define PWM_CTL      0
#define PWM_STA      1
#define PWM_DMAC     2
#define PWM_RNG1     4
#define PWM_DAT1     5
#define PWM_FIFO     6
#define PWM_RNG2     8
#define PWM_DAT2     9

#define PWM_CTL_MSEN2 (1<<15)
#define PWM_CTL_PWEN2 (1<<8)
#define PWM_CTL_MSEN1 (1<<7)
#define PWM_CTL_CLRF1 (1<<6)
#define PWM_CTL_USEF1 (1<<5)
#define PWM_CTL_MODE1 (1<<1)
#define PWM_CTL_PWEN1 (1<<0)

#define PI_HW_PWM_MAX_FREQ 125000000
#define PI_HW_PWM_MAX_FREQ_2711 187500000

#define CLK_PLLD_FREQ      500000000
#define CLK_PLLD_FREQ_2711 750000000
#define PI_HW_PWM_RANGE 1000000

static uint32_t piPeriphBase = 0x20000000;

static volatile int pi_is_2711 = 0;

static volatile uint32_t * clkReg  = MAP_FAILED;

static volatile uint32_t hw_pwm_max_freq = PI_HW_PWM_MAX_FREQ;
static volatile uint32_t clk_plld_freq = CLK_PLLD_FREQ_2711;

static uint32_t hw_pwm_freq[2];
static uint32_t hw_pwm_duty[2];
static uint32_t hw_pwm_real_range[2];

static const uint8_t PWMDef[54] =
{
   /*          0     1     2     3     4     5     6     7     8     9 */
   /* 0 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   /* 1 */   0x00, 0x00, 0x84, 0x94, 0x00, 0x00, 0x00, 0x00, 0x82, 0x92,
   /* 2 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   /* 3 */   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   /* 4 */   0x84, 0x94, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00,
   /* 5 */   0x00, 0x00, 0x85, 0x95,
};

#define SYST_BASE  (piPeriphBase + 0x003000)
#define DMA_BASE   (piPeriphBase + 0x007000)
#define CLK_BASE   (piPeriphBase + 0x101000)
#define GPIO_BASE  (piPeriphBase + 0x200000)
#define UART0_BASE (piPeriphBase + 0x201000)
#define PCM_BASE   (piPeriphBase + 0x203000)
#define SPI0_BASE  (piPeriphBase + 0x204000)
#define I2C0_BASE  (piPeriphBase + 0x205000)
#define PWM_BASE   (piPeriphBase + 0x20C000)
#define BSCS_BASE  (piPeriphBase + 0x214000)
#define UART1_BASE (piPeriphBase + 0x215000)
#define I2C1_BASE  (piPeriphBase + 0x804000)
#define I2C2_BASE  (piPeriphBase + 0x805000)
#define DMA15_BASE (piPeriphBase + 0xE05000)

#define DMA_LEN   0x1000 /* allow access to all channels */
#define CLK_LEN   0xA8
#define GPIO_LEN  0xF4
#define SYST_LEN  0x1C
#define PCM_LEN   0x24
#define PWM_LEN   0x28
#define I2C_LEN   0x1C
#define BSCS_LEN  0x40

#define GPSET0 7
#define GPSET1 8

#define GPCLR0 10
#define GPCLR1 11

#define GPLEV0 13
#define GPLEV1 14

#define GPPUD     37
#define GPPUDCLK0 38
#define GPPUDCLK1 39

/* BCM2711 has different pulls */

#define GPPUPPDN0 57
#define GPPUPPDN1 58
#define GPPUPPDN2 59
#define GPPUPPDN3 60

#define SYST_CS  0
#define SYST_CLO 1
#define SYST_CHI 2

static volatile uint32_t  *gpioReg = MAP_FAILED;
static volatile uint32_t  *pwmReg = MAP_FAILED;
static volatile uint32_t  *systReg = MAP_FAILED;

#define PI_BANK (gpio>>5)
#define PI_BIT  (1<<(gpio&0x1F))

/* gpio modes. */

#define PI_INPUT  0
#define PI_OUTPUT 1
#define PI_ALT0   4
#define PI_ALT1   5
#define PI_ALT2   6
#define PI_ALT3   7
#define PI_ALT4   3
#define PI_ALT5   2

static void initHWClk
   (int clkCtl, int clkDiv, int clkSrc, int divI, int divF, int MASH)
{
   printf("ctl=%d div=%d src=%d /I=%d /f=%d M=%d\n",
      clkCtl, clkDiv, clkSrc, divI, divF, MASH);

   /* kill the clock if busy, anything else isn't reliable */

   if (clkReg[clkCtl] & CLK_CTL_BUSY)
   {
      do
      {
         clkReg[clkCtl] = BCM_PASSWD | CLK_CTL_KILL;
      }
      while (clkReg[clkCtl] & CLK_CTL_BUSY);
   }

   clkReg[clkDiv] = (BCM_PASSWD | CLK_DIV_DIVI(divI) | CLK_DIV_DIVF(divF));

   usleep(10);

   clkReg[clkCtl] = (BCM_PASSWD | CLK_CTL_MASH(MASH) | CLK_CTL_SRC(clkSrc));

   usleep(10);

   clkReg[clkCtl] |= (BCM_PASSWD | CLK_CTL_ENAB);
}

void gpioSetMode(unsigned gpio, unsigned mode)
{
   int reg, shift;

   reg   =  gpio/10;
   shift = (gpio%10) * 3;

   gpioReg[reg] = (gpioReg[reg] & ~(7<<shift)) | (mode<<shift);
}

int gpioGetMode(unsigned gpio)
{
   int reg, shift;

   reg   =  gpio/10;
   shift = (gpio%10) * 3;

   return (*(gpioReg + reg) >> shift) & 7;
}

/* Values for pull-ups/downs off, pull-down and pull-up. */

#define PI_PUD_OFF  0
#define PI_PUD_DOWN 1
#define PI_PUD_UP   2

void gpioSetPullUpDown(unsigned gpio, unsigned pud)
{
   int shift = (gpio & 0xf) << 1;
   uint32_t bits;
   uint32_t pull;

   if (pi_is_2711)
   {
      switch (pud)
      {
         case PI_PUD_OFF:  pull = 0; break;
         case PI_PUD_UP:   pull = 1; break;
         case PI_PUD_DOWN: pull = 2; break;
      }

      bits = *(gpioReg + GPPUPPDN0 + (gpio>>4));
      bits &= ~(3 << shift);
      bits |= (pull << shift);
      *(gpioReg + GPPUPPDN0 + (gpio>>4)) = bits;
   }
   else
   {
      *(gpioReg + GPPUD) = pud;

      usleep(20);

      *(gpioReg + GPPUDCLK0 + PI_BANK) = PI_BIT;

      usleep(20);
  
      *(gpioReg + GPPUD) = 0;

      *(gpioReg + GPPUDCLK0 + PI_BANK) = 0;
   }
}

int gpioRead(unsigned gpio)
{
   if ((*(gpioReg + GPLEV0 + PI_BANK) & PI_BIT) != 0) return 1;
   else                                         return 0;
}

void gpioWrite(unsigned gpio, unsigned level)
{
   if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
   else            *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}

void gpioTrigger(unsigned gpio, unsigned pulseLen, unsigned level)
{
   if (level == 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
   else            *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;

   usleep(pulseLen);

   if (level != 0) *(gpioReg + GPCLR0 + PI_BANK) = PI_BIT;
   else            *(gpioReg + GPSET0 + PI_BANK) = PI_BIT;
}

/* Bit (1<<x) will be set if gpio x is high. */

uint32_t gpioReadBank1(void) { return (*(gpioReg + GPLEV0)); }
uint32_t gpioReadBank2(void) { return (*(gpioReg + GPLEV1)); }

/* To clear gpio x bit or in (1<<x). */

void gpioClearBank1(uint32_t bits) { *(gpioReg + GPCLR0) = bits; }
void gpioClearBank2(uint32_t bits) { *(gpioReg + GPCLR1) = bits; }

/* To set gpio x bit or in (1<<x). */

void gpioSetBank1(uint32_t bits) { *(gpioReg + GPSET0) = bits; }
void gpioSetBank2(uint32_t bits) { *(gpioReg + GPSET1) = bits; }

unsigned gpioHardwareRevision(void)
{
   static unsigned rev = 0;

   FILE *filp;
   char buf[512];
   char term;
   int chars=4; /* number of chars in revision string */

   filp = fopen ("/proc/cpuinfo", "r");

   if (filp != NULL)
   {
      while (fgets(buf, sizeof(buf), filp) != NULL)
      {
         if (!strncasecmp("revision", buf, 8))
         {
            if (sscanf(buf+strlen(buf)-(chars+1),
               "%x%c", &rev, &term) == 2)
            {
               if (term != '\n') rev = 0;
               else rev &= 0xFFFFFF; /* mask out warranty bit */
            }
         }
      }

      fclose(filp);
   }

   if (filp = fopen("/proc/device-tree/soc/ranges" , "rb"))
   {
      if (fread(buf, 1, sizeof(buf), filp) >= 8)
      {
         piPeriphBase = buf[4]<<24 | buf[5]<<16 | buf[6]<<8 | buf[7];
         if (!piPeriphBase)
            piPeriphBase = buf[8]<<24 | buf[9]<<16 | buf[10]<<8 | buf[11];

         if (piPeriphBase == 0xFE000000)
         {
            pi_is_2711 = 1;

            hw_pwm_max_freq = PI_HW_PWM_MAX_FREQ_2711;
            clk_plld_freq = CLK_PLLD_FREQ_2711;

         }
         else
         {
            hw_pwm_max_freq = PI_HW_PWM_MAX_FREQ;
            clk_plld_freq = CLK_PLLD_FREQ;
         }
      }
      fclose(filp);
   }

   printf("2711 = %d, peri base = %x, rev = %x(%d)\n",
      pi_is_2711, piPeriphBase, rev, rev);

   return rev;
}

/* Returns the number of microseconds after system boot. Wraps around
   after 1 hour 11 minutes 35 seconds.
*/

uint32_t gpioTick(void) { return systReg[SYST_CLO]; }


/* Map in registers. */

static uint32_t * initMapMem(int fd, uint32_t addr, uint32_t len)
{
    return (uint32_t *) mmap(0, len,
       PROT_READ|PROT_WRITE|PROT_EXEC,
       MAP_SHARED|MAP_LOCKED,
       fd, addr);
}

int gpioInitialise(void)
{
   int fd;

   gpioHardwareRevision(); /* sets rev and peripherals base address */

   fd = open("/dev/mem", O_RDWR | O_SYNC) ;

   if (fd < 0)
   {
      fprintf(stderr,
         "This program needs root privileges.  Try using sudo\n");
      return -1;
   }

   gpioReg  = initMapMem(fd, GPIO_BASE,  GPIO_LEN);
   pwmReg  = initMapMem(fd, PWM_BASE,  PWM_LEN);
   clkReg  = initMapMem(fd, CLK_BASE,  CLK_LEN);
   systReg  = initMapMem(fd, SYST_BASE,  SYST_LEN);


   close(fd);

   if ((gpioReg == MAP_FAILED) ||
       (systReg == MAP_FAILED) ||
       (clkReg == MAP_FAILED) ||
       (pwmReg == MAP_FAILED))
   {
      fprintf(stderr,
         "Bad, mmap failed\n");
      return -1;
   }
   return 0;
}

int gpioHardwarePWM(
   unsigned gpio, unsigned frequency, unsigned dutycycle)
{
   uint32_t old_PWM_CTL;
   unsigned pwm, mode;
   uint32_t real_range, real_dutycycle;

   printf("gpio=%d  frequency=%d dutycycle=%d\n",
      gpio, frequency, dutycycle);

   if (gpio > 31)
      printf("bad gpio (%d)\n", gpio);

   if (!PWMDef[gpio])
      printf("bad gpio for PWM (%d)\n", gpio);

   if (dutycycle > 1000000)
      printf("bad PWM dutycycle (%d)\n", dutycycle);

   if (((frequency < 1) ||
        (frequency > hw_pwm_max_freq)) &&
        (frequency))
      printf(
         "bad hardware PWM frequency %d-%d: (%d)\n",
            1, hw_pwm_max_freq, frequency);


   pwm = (PWMDef[gpio] >> 4) & 3;
   mode  = PWMDef[gpio] & 7;

   if (frequency)
   {
      real_range = ((double)clk_plld_freq / (2.0 * frequency)) + 0.5;
      real_dutycycle = ((uint64_t)dutycycle * real_range) / PI_HW_PWM_RANGE;

      /* record the set PWM frequency and dutycycle */

      hw_pwm_freq[pwm] =
         ((double)clk_plld_freq / ( 2.0 * real_range)) + 0.5;

      hw_pwm_duty[pwm]  = dutycycle;

      hw_pwm_real_range[pwm] = real_range;

      /* preserve channel enable only and mark space mode */

      old_PWM_CTL = pwmReg[PWM_CTL] &
         (PWM_CTL_PWEN1 | PWM_CTL_MSEN1 | PWM_CTL_PWEN2 | PWM_CTL_MSEN2);

      pwmReg[PWM_CTL] = 0;

      usleep(10);

      initHWClk(CLK_PWMCTL, CLK_PWMDIV, CLK_CTL_SRC_PLLD, 2, 0, 0);

      if (pwm == 0)
      {
         pwmReg[PWM_RNG1] = real_range;
         usleep(10);
         pwmReg[PWM_DAT1] = real_dutycycle;
         usleep(10);

         pwmReg[PWM_CTL] = (old_PWM_CTL | PWM_CTL_PWEN1 | PWM_CTL_MSEN1);
      }
      else
      {
         pwmReg[PWM_RNG2] = real_range;
         usleep(10);
         pwmReg[PWM_DAT2] = real_dutycycle;
         usleep(10);

         pwmReg[PWM_CTL] = (old_PWM_CTL | PWM_CTL_PWEN2 | PWM_CTL_MSEN2);
      }

      gpioSetMode(gpio, mode);
      printf("range=%d dc=%d\n", real_range, real_dutycycle);

   }
   else
   {
      /* frequency 0, stop PWM */

      if (pwm == 0) pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN1);
      else          pwmReg[PWM_CTL] &= (~PWM_CTL_PWEN2);

   }

   return 0;
}


int main(int argc, char *argv[])
{
   int i, freq, gpio, dc;

   if (gpioInitialise() < 0) return 1;

   if (argc > 1) freq = atoi(argv[1]); else freq = 10;
   if (argc > 2) gpio = atoi(argv[2]); else gpio = 12;
   if (argc > 3) dc = atoi(argv[3]); else dc = 500000;

   gpioHardwarePWM(gpio, freq, dc);

   return 0;
}

@guymcswain
Copy link
Collaborator

If hw is broken then other libs should show the flaw?

@guymcswain
Copy link
Collaborator

Even the so-called stable frequency values have occasional disturbances - setting my scope to persistent display reveals some ghosting.

@joan2937
Copy link
Owner Author

Are these occasional disturbances just on the bcm2711 hardware?

wiringPi and bcm2835 have slightly odd hardware PWM implementations. It's not as simple as dialling in a frequency and dutycycle. I might have a look at their implementations. I'm not even sure if they work at all on the later Pis.

@guymcswain
Copy link
Collaborator

Are these occasional disturbances just on the bcm2711 hardware?

So far I'm only testing on my pi400 - presumably bcm2711C0.

More searches dredged up this thread from raspi forums. It is the very same issue. I responded to the OP at the time that I could not reproduce the issue on my Pi400. Now I am able to repro. Was there a firmware update along the way that broke it?

@joan2937
Copy link
Owner Author

No idea about firmware changes. I don't see how that would change the functioning of the PWM hardware though, not at the level we are using it. Anyhow I'm done for the day.

@joan2937
Copy link
Owner Author

joan2937 commented Feb 13, 2022

I am testing using the crystal oscillator rather than PLL D as the clock source for hardware PWM. I am going from 1 kHz to 1 MHz in 1 kHz steps. I'm using pigpio with 1 MHz sampling to detect the callbacks on a Pi400. Of course pigpio will fail to keep up way before I reach a frequency of 1 MHz but it seems okay so far.

Actually I can only test up to 100 KHz on the Pi400. The bottle neck is Python. piscope sees up to 500 kHz sort of okay.

I think I would bite the bullet and give up with PLLD on the BCM2711 (at least for the time being). The oscillator is 54 MHz rather than 750 MHz so we will lose a lot of high frequency PWM. The max PWM frequency would be 13.5 MHz rather than 187.5 MHz but who would try to use that anyhow?

@martijnt
Copy link

martijnt commented Feb 16, 2022

As far as most people are concerned, 13.5 Mhz would be more than enough ;-)

One more observation: If we use hardware pwm via pigpio on a rev 1.4 (pigs hp 12 10000 500000), and use omxplayer at the same time to play back an .mp4 file, omxplayer crashes with the following stack trace (it works on the rev 1.2, and on the rev 1.4 without hardware pwm active):

Feb 16 17:34:00 rev14 kernel: ------------[ cut here ]------------
Feb 16 17:34:00 rev14 kernel: WARNING: CPU: 1 PID: 1289 at drivers/firmware/raspberrypi.c:64 rpi_firmware_property_list+0x1f8/0x264
Feb 16 17:34:00 rev14 kernel: Firmware transaction timeout
Feb 16 17:34:00 rev14 kernel: Modules linked in: cmac bnep hci_uart btbcm bluetooth ecdh_generic ecc 8021q garp stp llc joydev vc4 cec drm_kms_helper v3d gpu_sched cdc_ether option usb_wwan usbserial brcmfmac brcmutil drm sha256_generic bcm2835_isp(C) cfg80211 raspberrypi_ts raspberrypi_hwmon rfkill bcm2835_codec(C) bcm2835_v4l2(C) bcm2835_mmal_vchiq(C) v4l2_mem2mem videobuf2_dma_contig videobuf2_vmalloc videobuf2_memops videobuf2_v4l2 snd_bcm2835(C) vc_sm_cma(C) videobuf2_common drm_panel_orientation_quirks snd_soc_core videodev snd_compress mc snd_pcm_dmaengine snd_pcm snd_timer rpivid_mem snd syscopyarea sysfillrect sysimgblt fb_sys_fops rpi_backlight uio_pdrv_genirq backlight uio nvmem_rmem ip_tables x_tables ipv6
Feb 16 17:34:00 rev14 kernel: CPU: 1 PID: 1289 Comm: kworker/1:2 Tainted: G         C        5.10.63-v7l+ #1496
Feb 16 17:34:00 rev14 kernel: Hardware name: BCM2711
Feb 16 17:34:00 rev14 kernel: Workqueue: events dbs_work_handler
Feb 16 17:34:00 rev14 kernel: Backtrace:
Feb 16 17:34:00 rev14 kernel: [<c0b83534>] (dump_backtrace) from [<c0b838c8>] (show_stack+0x20/0x24)
Feb 16 17:34:00 rev14 kernel:  r7:ffffffff r6:00000000 r5:60000013 r4:c12e6b3c
Feb 16 17:34:00 rev14 kernel: [<c0b838a8>] (show_stack) from [<c0b87cb4>] (dump_stack+0xcc/0xf8)
Feb 16 17:34:00 rev14 kernel: [<c0b87be8>] (dump_stack) from [<c0220b10>] (__warn+0xfc/0x114)
Feb 16 17:34:00 rev14 kernel:  r10:00000000 r9:00000009 r8:c09bd064 r7:00000040 r6:00000009 r5:c09bd064
Feb 16 17:34:00 rev14 kernel:  r4:c0ea16c4 r3:c1205094
Feb 16 17:34:00 rev14 kernel: [<c0220a14>] (__warn) from [<c0b8406c>] (warn_slowpath_fmt+0xa4/0xd8)
Feb 16 17:34:00 rev14 kernel:  r7:00000040 r6:c0ea16c4 r5:c1205048 r4:c0ea16e4
Feb 16 17:34:00 rev14 kernel: [<c0b83fcc>] (warn_slowpath_fmt) from [<c09bd064>] (rpi_firmware_property_list+0x1f8/0x264)
Feb 16 17:34:00 rev14 kernel:  r9:00000018 r8:c1205048 r7:c1a7d440 r6:dac03000 r5:00001000 r4:00000012
Feb 16 17:34:00 rev14 kernel: [<c09bce6c>] (rpi_firmware_property_list) from [<c09bd140>] (rpi_firmware_property+0x70/0x118)
Feb 16 17:34:00 rev14 kernel:  r10:c2cb8e4c r9:00030002 r8:00000018 r7:c1a7d440 r6:c51d9d48 r5:0000000c
Feb 16 17:34:00 rev14 kernel:  r4:c2cb8e40
Feb 16 17:34:00 rev14 kernel: [<c09bd0d0>] (rpi_firmware_property) from [<c07f01ec>] (raspberrypi_clock_property+0x54/0x7c)
Feb 16 17:34:00 rev14 kernel:  r10:00000000 r9:00000000 r8:c1b5e000 r7:00000000 r6:29b92700 r5:c51d9d70
Feb 16 17:34:00 rev14 kernel:  r4:c1205048 r3:0000000c
Feb 16 17:34:00 rev14 kernel: [<c07f0198>] (raspberrypi_clock_property) from [<c07f0260>] (raspberrypi_fw_get_rate+0x4c/0x70)
Feb 16 17:34:00 rev14 kernel:  r5:00000000 r4:c1205048
Feb 16 17:34:00 rev14 kernel: [<c07f0214>] (raspberrypi_fw_get_rate) from [<c07e6920>] (clk_recalc+0x44/0x84)
Feb 16 17:34:00 rev14 kernel:  r4:c1b809c0
Feb 16 17:34:00 rev14 kernel: [<c07e68dc>] (clk_recalc) from [<c07e6c24>] (__clk_recalc_rates+0x30/0x94)
Feb 16 17:34:00 rev14 kernel:  r5:00000000 r4:c1b809c0
Feb 16 17:34:00 rev14 kernel: [<c07e6bf4>] (__clk_recalc_rates) from [<c07e6ce0>] (clk_core_get_rate_recalc+0x58/0x5c)
Feb 16 17:34:00 rev14 kernel:  r7:00000000 r6:c1205048 r5:2faf0800 r4:c1b809c0
Feb 16 17:34:00 rev14 kernel: [<c07e6c88>] (clk_core_get_rate_recalc) from [<c07e6d0c>] (clk_get_rate+0x28/0x38)
Feb 16 17:34:00 rev14 kernel:  r5:2faf0800 r4:c1b5e000
Feb 16 17:34:00 rev14 kernel: [<c07e6ce4>] (clk_get_rate) from [<c0988120>] (dev_pm_opp_set_rate+0x70/0x588)
Feb 16 17:34:00 rev14 kernel:  r5:2faf0800 r4:c22c7400
Feb 16 17:34:00 rev14 kernel: [<c09880b0>] (dev_pm_opp_set_rate) from [<c0993028>] (set_target+0x38/0x3c)
Feb 16 17:34:00 rev14 kernel:  r10:00000000 r9:00000000 r8:00000002 r7:00000000 r6:c1406e80 r5:c1205048
Feb 16 17:34:00 rev14 kernel:  r4:c22c7600
Feb 16 17:34:00 rev14 kernel: [<c0992ff0>] (set_target) from [<c098dd14>] (__cpufreq_driver_target+0x1bc/0x540)
Feb 16 17:34:00 rev14 kernel: [<c098db58>] (__cpufreq_driver_target) from [<c09910bc>] (od_dbs_update+0xc4/0x170)
Feb 16 17:34:00 rev14 kernel:  r10:00000000 r9:c3faab80 r8:c36f8900 r7:c3faab00 r6:c3faab80 r5:c3faab00
Feb 16 17:34:00 rev14 kernel:  r4:c22c7600
Feb 16 17:34:00 rev14 kernel: [<c0990ff8>] (od_dbs_update) from [<c0992320>] (dbs_work_handler+0x3c/0x64)
Feb 16 17:34:00 rev14 kernel:  r9:00000000 r8:c131d4c4 r7:c22c7600 r6:c3faab04 r5:00000000 r4:c3faab38
Feb 16 17:34:00 rev14 kernel: [<c09922e4>] (dbs_work_handler) from [<c023db68>] (process_one_work+0x250/0x5a0)
Feb 16 17:34:00 rev14 kernel:  r9:00000000 r8:00000040 r7:eff08a00 r6:eff056c0 r5:c3167180 r4:c3faab38
Feb 16 17:34:00 rev14 kernel: [<c023d918>] (process_one_work) from [<c023df18>] (worker_thread+0x60/0x5c4)
Feb 16 17:34:00 rev14 kernel:  r10:eff056c0 r9:c1203d00 r8:eff056d8 r7:00000008 r6:eff056c0 r5:c3167194
Feb 16 17:34:00 rev14 kernel:  r4:c3167180
Feb 16 17:34:00 rev14 kernel: [<c023deb8>] (worker_thread) from [<c02459f8>] (kthread+0x170/0x174)
Feb 16 17:34:00 rev14 kernel:  r10:c1a4be74 r9:c3167180 r8:c023deb8 r7:c51d8000 r6:00000000 r5:c4e463c0
Feb 16 17:34:00 rev14 kernel:  r4:c3f3e140
Feb 16 17:34:00 rev14 kernel: [<c0245888>] (kthread) from [<c02000ec>] (ret_from_fork+0x14/0x28)
Feb 16 17:34:00 rev14 kernel: Exception stack(0xc51d9fb0 to 0xc51d9ff8)
Feb 16 17:34:00 rev14 kernel: 9fa0:                                     00000000 00000000 00000000 00000000
Feb 16 17:34:00 rev14 kernel: 9fc0: 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000
Feb 16 17:34:00 rev14 kernel: 9fe0: 00000000 00000000 00000000 00000000 00000013 00000000
Feb 16 17:34:00 rev14 kernel:  r10:00000000 r9:00000000 r8:00000000 r7:00000000 r6:00000000 r5:c0245888
Feb 16 17:34:00 rev14 kernel:  r4:c4e463c0
Feb 16 17:34:00 rev14 kernel: ---[ end trace b29802016c18d7aa ]---
Feb 16 17:34:00 rev14 kernel: cpu cpu0: dev_pm_opp_set_rate: failed to find current OPP for freq 4294967186 (-34)
Feb 16 17:34:01 rev14 kernel: raspberrypi-clk soc:firmware:clocks: Failed to change fw-clk-arm frequency: -110
Feb 16 17:34:03 rev14 kernel: hwmon hwmon1: Failed to get throttled (-110)
Feb 16 17:34:04 rev14 kernel: cpu cpu0: dev_pm_opp_set_rate: failed to find current OPP for freq 4294967186 (-34)
Feb 16 17:34:05 rev14 kernel: raspberrypi-clk soc:firmware:clocks: Failed to change fw-clk-arm frequency: -110

When this happens, the display freezes, and a power cycle is required to get the Pi working again. It looks like the Raspberry Pi firmware is doing something on the rev 1.4 which it is not doing (or differently) on the rev 1.2.

@martijnt
Copy link

My plan is to put together an example using another library to do the hardware PWM to compare this with.

@joan2937
Copy link
Owner Author

@martijnt

Both the wiringPi and the bcm2835 libraries use the crystal oscillator as the PWM clock source. They should both be okay.

@guymcswain
Copy link
Collaborator

FWIW:
vcgencmd measure_clock plld
frequency(100)=3000000000 # versus ?

vcgencmd measure_clock pwm
frequency(25)=375007328 # versus 750 MHz

@martijnt
Copy link

pi@rev11:~ $ vcgencmd measure_clock plld && vcgencmd measure_clock pwm
frequency(100)=3000000000
frequency(25)=107143064
pi@rev12:~ $ vcgencmd measure_clock plld && vcgencmd measure_clock pwm
frequency(100)=3000000000
frequency(25)=374994144
pi@rev14:~ $ vcgencmd measure_clock plld && vcgencmd measure_clock pwm
frequency(100)=3000000000
frequency(25)=107143064

@danieltham
Copy link

While we are on the Pi4B, i wanted to ask if its recommended/not recommended to use pigpio library with RPi.gpio library in a single project?

@DennisMikkelson
Copy link

I see this issue is still open. One symptom that was mentioned is the erratic behavior of the pwm signal in cases where it was not working correctly, and the fact that an oscilloscope could not sync properly on the signal. That is how "balanced" hardware pwm output appears. The pigpio documentation says that pigpio hardware pwm always uses mark-space. Is it possible that mark-space mode is not always properly initiated, or that something is switching the mode from mark-space to balanced in some cases?

@guymcswain
Copy link
Collaborator

The pigpio documentation says that pigpio hardware pwm always uses mark-space.

I'm having trouble finding this. Can you provide a link? TIA

@joan2937
Copy link
Owner Author

I can't find mark space mentioned in the docs either (perhaps it was an answer to a question/issue).. It is true though. pigpio only sets mark space mode,

Our problem remains that the documentation for the Pi4B etc. shows no material changes to the PWM hardware.

@DennisMikkelson
Copy link

Sorry, about my statement that the pigpio docs say pigpio hardware pwm always uses mark-space. That statement appears in a comment from joan in the discussion at: https://forums.raspberrypi.com/viewtopic.php?t=244692. As I was switching between the pigpio docs and various web site discussions, I incorrectly remembered that statement as being in the pigpio docs.
Before switching to 64-bit bullseye, I was using wiring pi. If mark-space was not specified, wiring pi hardware pwm defaulted to balanced mode. The description of failure to sync and erratic displays on an oscilloscope reminded me of what I saw using balanced mode in wiring pi. The comment by guymcswain (earlier in this thread) that switching between a terminal window and browser window switched behavior between erratic and correct raises the possibility that something is causing a switch between mark-space and balanced mode. Could this be a software problem, where some lower-level OS code triggers a change in the gpio pin mode? Could it be a hardware problem where a change in CPU load causes a "glitch" that switches it back to balanced mode? Would it be possible to test this with a crude hack of pigpiod that repeatedly sets mark-space mode?

@hongpan0507
Copy link

I bought 3 raspiberry pi 4 from amazon last week. All of them have been identified as v1.4. All of them have the same issue as described by this thread. 2 of the pi 4 doesn't have any PWM output from Pin 12. one of the pi 4 has PWM output with pulse width changing over a few pulses on its own when seen using oscilloscope. Just like others reported here, everything works well on pi 3. I have another pi 4, purchased a year before, not v1.4, works just fine; No issue with PWM on pin 12.
Another thing to note is that on pi 4, v1.4, PWM channel output (pin 13) is not cleaning, it has a short and sharp dip towards the end of the pulse on, it is bad enough to cause the oscilloscope to trigger improperly if trigger level is left at the half of the pulse on amplitude. Probably doesn't matter when serving as a PWM output, but it makes me wonder if the layout designer was paying attention to signal integrity and EMI during layout.
Please let me know if there is a work around.

@willianwrm
Copy link

I have a Pi4B Rev 1.4 (b03114), tested several frequencies and all of them are buggy: a duty of 50% prints something 20% ~ 50% randomly.

But then I did a simple test: fixed the CPU frequency to maximum (did run some heavy load program at other window, forcing the CPU to maximum) and like magic all frequencies and duty values worked like a charm.

So I think it could be something related to the new chipset stepping, maybe the firmware is not prepared correctly.

My setup:
Raspberry: Pi4 Model B
Revision: b03114 (1.4)
System: Raspberry Pi OS September 22nd 2022 (tested 32bits and 64bits)

@guymcswain
Copy link
Collaborator

Has anyone experimented with DVFS which is unique to Pi4/Pi400/CM4?

dvfs=2 fixed voltage for default operating frequencies

Place dvfs=2 in /boot/config.txt

@joan2937
Copy link
Owner Author

I added the line to my Pi400 /boot/config.txt.

Now commented out as the Pi400 did not boot with the line present.

#dvfs=2

@guymcswain
Copy link
Collaborator

I found @willianwrm 's results interesting: Essentially forcing the system out of dynamic frequency scaling. I was hoping that fixing the voltage scaling would help.

@yusufsakr
Copy link

yusufsakr commented Oct 26, 2023

Hi, i got a similar problem with my RPI4 Rev 1.4 when "sudo insmod pwm.ko", a PWM driver created in c++ and have been tested before on RPI 3.
But the problem is "Segmentation Fault" with this dmesg Content, despite the fact that PWM Works when i tried it with Python code.

dmesg :-

[  534.960283] pwm: loading out-of-tree module taints kernel.
[  534.960868] hello world
[  534.960880] pwm_driver_init retval = 0 - registered Device number Major : 236 - Minor 0
[  534.961156] Device Driver has been Created Succesfully XD
[  534.961174] Unable to handle kernel paging request at virtual address fffffffffffffe40
[  534.961183] Mem abort info:
[  534.961188]   ESR = 0x0000000096000005
[  534.961193]   EC = 0x25: DABT (current EL), IL = 32 bits
[  534.961200]   SET = 0, FnV = 0
[  534.961205]   EA = 0, S1PTW = 0
[  534.961210]   FSC = 0x05: level 1 translation fault
[  534.961215] Data abort info:
[  534.961219]   ISV = 0, ISS = 0x00000005
[  534.961224]   CM = 0, WnR = 0
[  534.961229] swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000001135000
[  534.961236] [fffffffffffffe40] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
[  534.961255] Internal error: Oops: 0000000096000005 [#1] PREEMPT SMP
[  534.961261] Modules linked in: pwm(O+) rfcomm cmac algif_hash aes_arm64 aes_generic algif_skcipher af_alg bnep hci_uart btbcm bluetooth ecdh_generic ecc libaes 8021q garp stp llc brcmfmac brcmutil vc4 cfg80211 snd_soc_hdmi_codec drm_display_helper cec drm_dma_helper drm_kms_helper rfkill v3d bcm2835_codec(C) snd_soc_core raspberrypi_hwmon gpu_sched rpivid_hevc(C) bcm2835_v4l2(C) bcm2835_isp(C) drm_shmem_helper v4l2_mem2mem bcm2835_mmal_vchiq(C) snd_compress i2c_brcmstb videobuf2_vmalloc videobuf2_dma_contig snd_pcm_dmaengine snd_bcm2835(C) snd_pcm videobuf2_memops videobuf2_v4l2 videobuf2_common syscopyarea videodev snd_timer sysfillrect snd sysimgblt vc_sm_cma(C) mc fb_sys_fops uio_pdrv_genirq uio nvmem_rmem drm i2c_dev fuse drm_panel_orientation_quirks backlight ip_tables x_tables ipv6
[  534.961387] CPU: 3 PID: 3858 Comm: insmod Tainted: G         C O       6.1.21-v8+ #1642
[  534.961394] Hardware name: Raspberry Pi 4 Model B Rev 1.4 (DT)
[  534.961398] pstate: 60000005 (nZCv daif -PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[  534.961403] pc : pwm_driver_init+0x18c/0x1000 [pwm]
[  534.961420] lr : pwm_driver_init+0x15c/0x1000 [pwm]
[  534.961430] sp : ffffffc00aa9baa0
[  534.961433] x29: ffffffc00aa9baa0 x28: ffffffc00aa9bce0 x27: 0000000000000001
[  534.961442] x26: ffffffee11d1d000 x25: ffffffee11d1d000 x24: ffffffee11d1d000
[  534.961449] x23: ffffffee11d1d040 x22: ffffffee11d1d000 x21: ffffffee11d1c120
[  534.961457] x20: 0000000000000000 x19: ffffffee11d1d4c0 x18: 0000000000000000
[  534.961465] x17: 77703d4d45545359 x16: ffffffee8e8a4780 x15: 5f6d77702f646f6d
[  534.961472] x14: 0000000000000040 x13: 445820796c6c7566 x12: ffffffee8f5e73b0
[  534.961480] x11: 0000000000000040 x10: ffffffee8f69dbe8 x9 : ffffffee8e8a4804
[  534.961487] x8 : 0000000000017fe8 x7 : c0000000ffffefff x6 : 0000000000000000
[  534.961495] x5 : 0000000000000000 x4 : ffffff8053233d80 x3 : ffffffee8f69dbc0
[  534.961502] x2 : 0000000000000000 x1 : 000000001dcd6500 x0 : fffffffffffffdfb
[  534.961510] Call trace:
[  534.961513]  pwm_driver_init+0x18c/0x1000 [pwm]
[  534.961523]  do_one_initcall+0x54/0x2a0
[  534.961533]  do_init_module+0x50/0x208
[  534.961543]  load_module+0x1a3c/0x1d90
[  534.961550]  __do_sys_finit_module+0xc4/0x110
[  534.961556]  __arm64_sys_finit_module+0x28/0x38
[  534.961563]  invoke_syscall+0x4c/0x110
[  534.961570]  el0_svc_common.constprop.3+0xfc/0x120
[  534.961577]  do_el0_svc+0x34/0xd0
[  534.961582]  el0_svc+0x30/0x88
[  534.961590]  el0t_64_sync_handler+0x98/0xc0
[  534.961596]  el0t_64_sync+0x18c/0x190
[  534.961604] Code: 14000021 f9408ee1 aa1603f9 37f80221 (a9438c02) 
[  534.961652] ---[ end trace 0000000000000000 ]---

The Error starts @ ...

struct pwm_device* pwm_0 = NULL;
uint64_t pwm_high = 500000000;   //500 Mega Hz
pwm_config (pwm_0, pwm_high, 1000000000);

@chagenmaier-cpi
Copy link

Apparently we're still without a solution to this problem.
I am attempting to create a simple 20kHz, 50% duty cycle on gpio12. My Pi4 (version 1.5) behaves well from 1 kHz to 5 kHz and at 200 kHz. (I haven't characterized it at more frequencies.) A fixed cpu clock frequency doesn't help. All of this is consistent with other posters.

Has anyone come up with a work-around?

@chagenmaier-cpi
Copy link

For what it's worth, it appears that the gpio pin tries to set at the correct time. Using a scope I capture tiny pulses at the appropriate frequency.
Capture

@guymcswain
Copy link
Collaborator

guymcswain commented Nov 25, 2023

Yeah, this one is still unresolved.

Make sure you don’t have anything associated with audio running or any other gpio libraries installed.

Also, if you are running pigpiod as a service, disable it, reboot and try running from the command line.

@chagenmaier-cpi
Copy link

chagenmaier-cpi commented Nov 27, 2023

More info
In my particular case the hardware PWM seems to work up to about 5 kHz. Up to almost 50 kHz it doesn't. At first glance it looks like it works above the frequency, but in fact it sometimes generates short pulses (lower duty cycle). Here's an example at 50 kHz 50% d.c.,
image
At 35 kHz
image
At 30 kHz, not only are there missing pulses (indicated by the little tick marks) what looks like a good pulse has the wrong duration. It should be 16.5 usec but is only ~11 usec.
image

If I can summarize what we know:

  1. It happens only for revision 1.4 or later
  2. Slow frequency seems to work okay. "Slow frequency" may vary from board to board.
  3. At all frequencies, the pin "tries". Runt pulses can be seen on the pin at the appropriate intervals. The runt pulses are short relative to the rise/fall time of the pin - they reach only a few hundred millivolts.

There has been some talk about audio, etc., but, frankly, I don't see any hard evidence. I admit I'm not an expert here, but it seems to me that there are two reasonable causes:

  1. something else is manipulating either the GPIO pin or the PWM module
  2. there's a hardware bug in the PWM module.

#1 seems unlikely, given that it shows up only on newer hardware.

Is there any way to actually track this down either with the Pi people or with Broadcom? Or are we doomed to live in the dark?
Does anyone know if Pi5 is equally broken?

@TULA1000
Copy link

I have the same problem but on CM4. PWM0 on gpio 12 works fine when using sysfs (/sys/class/pwm/pwmchip0/). But when i try to use gpioHardwarePWM with frequencies 880, 10000, 20000... and dutycycle 50% signal becomes wrong. After testing on diffrents CM4 we have it appears that this happens on CM4 2 GB ram (b03140) BUT gpioHardwarePWM works fine on CM4 4 GB (c03140). I don't know why an amount of ram affects this(there are no other diffrences between CM4(there is only one revision of CM4) as far as i know).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants