nRF5340 PWM limitations undocummented

Hi all !

I recently faced an weird issue with a nRF5340 (on a DK board, and then a custom PCB).

When writting to the PWM peripheral, configured to some GPIO pins, some remained inactives.

First, let quote the documentation : nRF5340 PWM Peripheral, pins :

Pin configuration

The OUT[n] (n=0..3) signals associated with each PWM channel are mapped to physical pins according to the configuration of PSEL.OUT[n] registers. If PSEL.OUT[n].CONNECT is set to Disconnected, the associated PWM module signal will not be connected to any physical pins.

The PSEL.OUT[n] registers and their configurations are used as long as the PWM module is enabled and the PWM generation active (wave counter started). They are retained only as long as the device is in System ON mode (see the POWER section for more information about power modes).

To ensure correct behavior in the PWM module, the pins that are used must be configured in the GPIO peripheral in the following way before the PWM module is enabled:
Table 2. Recommended GPIO configuration before starting PWM generation PWM signal 	PWM pin 	Direction 	Output value 	Comment
OUT[n] 	As specified in PSEL.OUT[n] (n=0..3) 	Output 	0 	Idle state defined in GPIO OUT register

The idle state of a pin is defined by the OUT register in the GPIO module, to ensure that the pins used by the PWM module are driven correctly. If PWM generation is stopped by triggering a STOP task, the PWM module itself is temporarily disabled or the device temporarily enters System OFF. This configuration must be retained in the GPIO for the selected pins (I/Os) for as long as the PWM module is supposed to be connected to an external PWM circuit.

Only one peripheral can be assigned to drive a particular GPIO pin at a time. Failing to do so may result in unpredictable behavior.

We can clearly see that the PWM output can be configured to any GPIO, but, and that's here the issue : This is not the case. I've tried this sample of code : 

    for (uint8_t k = 0; k < NRF_PWM_CHANNEL_COUNT; k++)
        err -= pwm_set(Target[k].dev, k, Target[k].period, pulses[k], Target->flags);

that configure pulse lenght (from a well defined algorithm that compute a list of pulses length (for each channels) from an input angle for a servo engine. Using a debugger, the computed values are perfectly fine.

But, when looking at the pins with a scope, I've seen something weird : Only some channels were working, remaining channels were not (but there were some activity right after boot (goes to '1' or '0').

After spending some hours to seeks, I found something on the devicetree.

This is the working one :

// Pin muxing configuration
&pinctrl {
    // This first group is unused, and is pointing to the leds on the dk.
    pwm0_dk: pwm0_dk {
        group1 {
            psels =     <NRF_PSEL(PWM_OUT0, 0, 28)>,
                        <NRF_PSEL(PWM_OUT1, 0, 29)>,
                        <NRF_PSEL(PWM_OUT2, 0, 30)>, 
                        <NRF_PSEL(PWM_OUT3, 0, 31)>;
        };
    };
    pwm0_topaze: pwm0_topaze {
        group1 {
            psels =     <NRF_PSEL(PWM_OUT0, 1, 14)>,
                        <NRF_PSEL(PWM_OUT1, 1, 12)>, 
                        <NRF_PSEL(PWM_OUT2, 1, 0)>,
                        <NRF_PSEL(PWM_OUT3, 1, 4)>;
        };
    };
};

And this one expose some defective channels (CH3, config 0)

// Pin muxing configuration
&pinctrl {
    // This first group is unused, and is pointing to the leds on the dk.
    pwm0_dk: pwm0_dk {
        group1 {
            psels =     <NRF_PSEL(PWM_OUT0, 0, 28)>,
                        <NRF_PSEL(PWM_OUT1, 0, 29)>,
                        <NRF_PSEL(PWM_OUT2, 0, 30)>, 
                        <NRF_PSEL(PWM_OUT3, 1, 1)>;
        };
    };
    pwm0_topaze: pwm0_topaze {
        group1 {
            psels =     <NRF_PSEL(PWM_OUT0, 1, 14)>,
                        <NRF_PSEL(PWM_OUT1, 1, 12)>, 
                        <NRF_PSEL(PWM_OUT2, 1, 0)>,
                        <NRF_PSEL(PWM_OUT3, 1, 4)>;
        };
    };
};

The only difference on the second is the fact that the PWM use at least a pin on both ports (and the non working pin was the channel 3, defined on another port...).

I haven't seen this limitation on the documentation (web or pdf file). After searching a little bit, I've seen such a limitation on the nRF54L15 ICs.

Since I've seen it on other chips, but not on the nRF5340, I suppose it's more an error on the datahseet rather than a software / hardware bug (in the meaning, it's perfectly normal and wanted behavior).

I didn't know where to post that, so I did just open an devzone forum, if it's not appropriate could you redirect me to the right place ?

Thanks !

HEYWANG Léonard.

Parents
  • Hello Heywang,

    I am a little confused with the description here. I understand that you posted two code snippets of a pinctrl node, with the first snippet shows something that works, while the second shows something that does not work.

    However, the two snippets only differ in the pwm0_dk sub node, which has the comment that it is unused. The other sub node, pwm0_topaze, is the same in the two snippets.

    Could you please clarify some more here?

    Hieu

Reply
  • Hello Heywang,

    I am a little confused with the description here. I understand that you posted two code snippets of a pinctrl node, with the first snippet shows something that works, while the second shows something that does not work.

    However, the two snippets only differ in the pwm0_dk sub node, which has the comment that it is unused. The other sub node, pwm0_topaze, is the same in the two snippets.

    Could you please clarify some more here?

    Hieu

Children
  • Hi !

    I'm sorry for the comment that confused you. I'm working on a project with multiples persons (a friend and teachers). Furthermore, I own an nRF5340DK, and we have developed our custom PCB.

    Since I'm the only one who own a DK, the unused comment is more for the others (In the meaning : Don't use it, it won't work since the pins aren't matched). I personally use the DK and a custom pinctrl overlay that align pins in a row, making it easier to plug scope and develop.

    So yes, the "unused" overlay is, in fact, used.

    And while I was developing on it, when the last channel was configured on port 1, it remains at a high state, ignoring any Zephyr API call to set the pulse length. And immediately after setting it to port 0 (same as the others), it started working.

  • I think you might have a pin assignment conflict. By default, the nRF5340 DK has P1.01 used for UART TXD. Could you please check the DeviceTree to see if it is still being used for that purpose?

  • Hi !

    It's not the case, since I'm using a custom board for the project (defined with the tool). So UART is actually on custom pins also.

    And I checked ALL pins, since I got this situation before, a conflict, and the pins weren't working fine (logic, and this case is documented as unpredictable behavior on the documentation). So, I've listed all pins and their functions before writing here.

    And the fact that I've seen this kind of limitations on other chips give me the hint that is more something documentation related rather than something linked to my software config.

  • Could you please share your compiled application zephyr.dts?

Related