This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PWM doesn't work when SPI used

Hi,

I intitialized PWM1 instance:

    nrf_drv_pwm_config_t const config1 =
    {
        .output_pins = {
        2,                               // channel 0
        31,             // channel 1
        27,             // channel 2
        NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
    },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock = NRF_PWM_CLK_125kHz,
        .count_mode = NRF_PWM_MODE_UP,
        .top_value = 100,
        .load_mode = NRF_PWM_LOAD_INDIVIDUAL,
        .step_mode = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm1, &config1, NULL));

I use PWM1 to generate constant PWM signal with nrf_drv_pwm_simple_playback(m_pwm1, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);

I also initialized SPI0 (I really don't use MOSI and SCK pins of SPI):

    nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(&tx, 1, &rx0, 1);

    nrfx_spim_config_t spi_config = NRFX_SPIM_DEFAULT_CONFIG;
    spi_config.frequency      = NRF_SPIM_FREQ_8M;
    spi_config.miso_pin       = 26;
    spi_config.mosi_pin       = NRFX_SPIM_PIN_NOT_USED;
    spi_config.sck_pin        = NRFX_SPIM_PIN_NOT_USED;
    APP_ERROR_CHECK(nrfx_spim_init(&spi0, &spi_config, spim0_event_handler, NULL));
    
    APP_ERROR_CHECK(nrfx_spim_xfer(&spi0, &xfer_desc, NRFX_SPIM_FLAG_HOLD_XFER));

This way PWM1.channel1 doesn't work, no PWM is present.

If I change initialization of SPI0:

spi_config.sck_pin        = 0xFE; // anything other than 0xFF

than  PWM1.channel1 works as expected.

Any idea why is this happening?

  • I think there is some misunderstanding here; the assumption is that SPI is not SPI unless there is at least SCK and MOSI, and so there is no option to use NRFX_SPIM_PIN_NOT_USED as a pin number for SCK. Yes you can try, but it won't work and will have unpredictable results since it will attempt to set a non-existent bit field but will probably succeed in using the active bit field and select a physical pin corresponding to that, hence the difference between FF and FE. Should there be yet more levels of macros to stop one doing that? Please no ...

    Anyway this code is always going to be applied regardless of the port pin specified, valid or not  .. pin P0.31 or P0.30 (probably)  in the case of nRF52832 and 0xFF and 0xFE, P1.31 and P1.30 on nRF52840 but that's just a guess .. oh, and look that's the same pin as the PWM!

        nrf_gpio_cfg(p_config->sck_pin,
                     NRF_GPIO_PIN_DIR_OUTPUT,
                     NRF_GPIO_PIN_INPUT_CONNECT,
                     NRF_GPIO_PIN_NOPULL,
                     NRF_GPIO_PIN_S0S1,
                     NRF_GPIO_PIN_NOSENSE);
    

  • I want to read a logic value of some pin once some event occurs (within several microseconds). I can't do it in interrupt as there is softdevice running on nrf52 so the interrupts have some latency (hundreds of microseconds). I try to use SPI for this. The event is connected via PPI to SPI TX start. SPI samples logic value on the pin and using dma it stores it in RAM. I can later see what value was on that pin when the event occured.

    So, is there any possibility to run SPI without MOSI and SCK (as I don't need them in my case)? I can't assign MOSI and SCK to some unused pins as my nrf52 module's pins are fully occupied.

  • SPI will not do what you are looking for, as there is no event capture on MISO without both SCLK and CS active, SPI is simply the wrong approach.

    As I understand your requirement, this is traditionally done by a hardware-triggered counter driven by the port pin, so instead use a Timer/Counter or Comparator. The Timer/counter on nRF52 unusually doesn't allow port pin input directly, but you can use PPI to connect a port pin transition (High-Low or Low-High) to a Count Event, which in turn increments a hardware register (interrupt not required) so you can read to see how many transitions occurred regardless of SD activity. The Comparator allows the same functionality, but only shows a single event but can use the port pin direct without PPI.

    If it is only a single pin transition you are looking for, the Counter seems the best option, but if you are reading multiple pins triggered by a single pin transition then the PPI has to trigger a port read which if you can't rely on interrupts is somewhat problematic. You can use multiple Counters. of course; there is even the Quadrature encoder which is designed to capture 2-input sequencing.

    Edit: I see you have an event already, and are not using a port pin as the event. I think you could use the Event to Stop the comparator, which would then hold the pin state at the last transition until a new Start was issued.

  • Hi and thanks for your reply. I don't think the solution with Timer/Counter will work for me. I don't need to just count events. I need to buffer value of a pin on some event.

    The comparator (or A/D converter triggered by the event) will work, but unfortunately my signal is not connected to A/D enabled pin.

    I think the SPI approach will be good as long as I define SCK pin. The documentation mentions that MOSI, MISO and CS pins are optional. If I provide valid SCK pin (and MISO pin which I want to be sampled by SPI) then I can buffer my signal. Tested and it seems to be working solution. Fortunately I found one pin on my board which I can use as SCK.

Related