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

Force SPI transfer and a PWM signal in sync.

I am trying to control a current measurement chip (DDC114) that works with a protocol that is close (enough) to SPI. It has 2 channels, s.t. it can be read out and integrating at the same time. The switch between the channels is performed by an external square wave signal that sets the integration time. I implemented this using a 50% duty cycle PWM. During half a period I need to clock out 80 bits via SPI. My problem is that the PWM signal is constantly drifting w.r.t. the SPI clocks. I can tolerate a bit of shifting (couple of us) but not that the SPI clocks fall into a different half period of the PWM signal. How can I sync them in phase?

Here is the code I use to test it.

#include <sys/param.h>
#include <string.h>
#include "variables.h"
#include "sdk_config.h"
#include <nrf_drv_spi.h>
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include <string>
using namespace std;
#include "app_pwm.h"

void pwm_ready_callback2(uint32_t pwm_id){}

void run_test(){
    ret_code_t err_code;

    APP_PWM_INSTANCE(PWM1,1);
    app_pwm_config_t pwm1_cfg = APP_PWM_DEFAULT_CONFIG_1CH(2*100, 25);
    pwm1_cfg.pin_polarity[0] = APP_PWM_POLARITY_ACTIVE_HIGH;
    err_code = app_pwm_init(&PWM1,&pwm1_cfg,pwm_ready_callback2);
    APP_ERROR_CHECK(err_code);
    app_pwm_enable(&PWM1);
    app_pwm_channel_duty_set(&PWM1, 0, 50);


    nrf_drv_spi_t m_spi_master_1 = NRF_DRV_SPI_INSTANCE(1);
    nrf_drv_spi_config_t spi_config2 = NRF_DRV_SPI_DEFAULT_CONFIG;
    spi_config2.ss_pin = -1;
    spi_config2.miso_pin = DDCDOUT;
    spi_config2.mosi_pin = SDO;
    spi_config2.sck_pin  = CLK;
    spi_config2.frequency = NRF_DRV_SPI_FREQ_2M;
    spi_config2.mode = NRF_DRV_SPI_MODE_0;

    err_code = nrf_drv_spi_init(&m_spi_master_1, &spi_config2, NULL);
    uint8_t payload[10];

    //loop it so I can see it better on the oscilloscope
    for (int i = 0; i < 20000 ; i++) {
        err_code = nrf_drv_spi_transfer(&m_spi_master_1, NULL, 0, &payload[0], 10);
        nrf_delay_us(500);
    }
    nrf_drv_spi_uninit(&m_spi_master_1);
}

int main(){
    run_test()
}
  • Hi,

    I saw a similar request not long ago: devzone.nordicsemi.com/.../

    My suggestion then was to use GPIOTE and PPI to trigger a task in the ADC on rising or falling edges of the PWM. Unfortunately the SPI in the nRF51 doesn't have the necessary tasks to start a transfer using PPI so you will have to do this in software. So my suggestion here is to trigger an interrupt on PWM edges and start the PWM transfer from within the interrupt service routine. If you chose to do this in an interrupt while running BLE concurrently you need to consider that the Softdevice might interrupt your business at any time (as discussed in the link above). If this is a problem you should have a look at the Radio Timeslot API.

Related