Guidance for using PWM on the Thingy:91

Hi there,

I've been working on a board support package for the Nordic Thingy:91 package and in particular, putting together a blinky app for it. I'm unable to get things working with the RGB LED via Pulse Width Modulation (PWM). This is my first exposure to PWM though and so there's probably something obvious I'm missing. I've also asked Nordic about the steps I'm taking with PWM on the Thingy:91, but I'd like to check here that my use of the Pwm HAL library is correct.

To setup the Pwm for insecure programs:


...and the 3 associated LEDs:


...which are passed respectively to a RgbLed type's new function:

        pwm.set_output_pin(pwm::Channel::C0, &lightwell_red_pin)
            .set_output_pin(pwm::Channel::C1, &lightwell_green_pin)
            .set_output_pin(pwm::Channel::C2, &lightwell_blue_pin);

My Blinky program then uses this board setup:

fn main() -> ! {
    let board = Board::take().unwrap();
    let mut timer = Timer::new(board.TIMER0_NS);

    let rgb_pwm = board.leds.rgb_led_1.pwm;


    let mut led_is_on = false;
    loop {
        if led_is_on {
        } else {
        led_is_on = !led_is_on;

My board support package along with its blinky example is here: thingy-91-nrf9160/ at master · titanclass/thingy-91-nrf9160 · GitHub. The board support package also pulls in a draft PR I've made that enables the PWM for the nRF9160: Enables PWM for the nRF9160 by huntc · Pull Request #311 · nrf-rs/nrf-hal · GitHub.

Is there something obvious missing? I'm able to debug my program on the Thingy:91 and step through the lines etc, but I'm not seeing any LED activity. But again, this is my first time using PWM.

Thanks for any help.

You need to call enable() on the pwm instance!

Thanks for replying. Are you sure though? Doing so makes no difference... is there a particular point at which the Pwm must be enabled?

Also, within the Pwm new method, there's this:

        pwm.enable.write(|w| w.enable().enabled());

...which implies it is already enabled, no?

From what i remember working on it, it needs to be enabled after you configure the output pins if i’m not mistaken...

Yeah, tried that. No difference... I really appreciate your answers though. I might try and get this working on the development board. From what you've said so far, it doesn't appear that what I'm doing is so wild. Thanks again for answering!

@kalkyl I've just tried the nrf-hal/examples/pwm-demo sample having flashed that to an nRF52840-dk. This doesn't appear to work for me either e.g. when I press button 1, I don't get any LED activity on the board.

I'm going to try debugging it next. Meanwhile, here are the commands I used to build and flash the device. Please let me know if there's something missing:

cd examples/pwm-demo
cargo objcopy --target thumbv7em-none-eabihf -- -O ihex ../../target/thumbv7em-none-eabihf/debug/pwm-demo.hex
nrfjprog -f nrf52 --program ../../target/thumbv7em-none-eabihf/debug/pwm-demo.hex --sectorerase

UPDATE 1: OK, so if I debug the program using Cortex-Debug - Visual Studio Marketplace and JLink then all is well... I can use the buttons to control the LEDs. However, if I stop my debugging and reset the device then it no longer works. This isn't a biggy for me, but I'm curious if you've observed similar behaviour. At least the Pwm code appears as though it still works and nothing has recently broken it.

UPDATE 2: I updated the blinky example for the nRF52840-dk bsp (which really needs an update!), and all is well (even when resetting). This shows that the Pwm code is fine in the way I want to use it for Blinky, which is:

fn main() -> ! {
    let nrf52 = Board::take().unwrap();

    let mut timer = Timer::new(nrf52.TIMER0);

    let pwm = Pwm::new(nrf52.PWM0);


    // Alternately flash the leds
    loop {
        delay(&mut timer, 250_000); // 250ms
        delay(&mut timer, 1_000_000); // 1s

I've now tried out the Thingy:91 bsp I've written (no good so far), the nrf-hal/example/pwm-demo (good) and the nRF52840-dk (good). Next stop is the nRF9160-dk with the same Blinky code as above.

Ahh yes the demo uses the DWT CYCCNT as the monotonic timer for the RTIC timer queue to provide the button debouncing functionality, and CYCCNT is only active while the debugger is attached on the nRF devices. I typically run the demo using cargo embed --target thumbv7em-none-eabihf
You'd have to implement the Monotonic trait for another timer on the device to have it work without the debugger (also note that this example is still on the old RTIC syntax, in the upcoming 0.6 release this is much more straight forward).

1 Like

Wow, the cargo embed approach is awesome! I had no idea that this existed. I will endeavour to update the READMEs when I push my sample forward. Thanks again. Now onto trying out my Blinky code on the nRF9160-dk.

UPDATE 1: I've created a new examples/pwm-blinky-demo project as part of my PR. It builds for the nRF52840 and the nRF9160. It works perfectly on the nRF52840, but not the nRF9160. Something obviously fishy then with my nRF9160 PWM enablement. Here's my PR, complete with the new example: Enables PWM for the nRF9160 by huntc · Pull Request #311 · nrf-rs/nrf-hal · GitHub. Thanks for any further pointers. I'm unsure what to look for next!

UPDATE 2: Blinky now works on the nRF9160. Unsure what I did. Still need to get the Thingy:91 working, but at least progress has been made.

UPDATE 3: The Thingy:91 now also works. The problem was that something was staying around on the flash device and prevented my app from being flashed correctly. I'm suspecting it was SPM related for both the nRF9160 and Thingy:91. Erasing all memory on the board enabled things to work.