Hello,
Currently, we trying to use PPI with the SPI module (we use the SDK 15.3.0)
We expected that the SPI makes one read transaction every 5 us ; to do this, we use 2 PPI channels with 2 timers.
One channel with one timer to toggle the slave select and the second channel with the second timer to start the SPI transfer.
We have followed :
infocenter.nordicsemi.com/index.jsp
devzone.nordicsemi.com/.../ppi-to-spim-task-how-to
#include <stdbool.h>
#include <stdint.h>
#include "nrf.h"
#include "nrf_gpiote.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "nrf_drv_ppi.h"
#include "nrf_drv_timer.h"
#include "nrf_drv_gpiote.h"
#include "nrf_drv_spi.h"
#include "app_error.h"
#include <nrf_log.h>
#include <nrf_log_ctrl.h>
#include <nrf_log_default_backends.h>
// Intialize pin part.
#define ADS7866_CS NRF_GPIO_PIN_MAP(0,11)
#define SPI_MISO_PIN NRF_GPIO_PIN_MAP(0, 7) // MISO signal P0.07
#define SPI_MOSI_PIN NRF_GPIO_PIN_MAP(0, 5) // MOSI signal P0.05
#define SPI_SCK_PIN NRF_GPIO_PIN_MAP(0, 8) // CLK signal P0.08
// Create SPI instance and configurations.
static nrf_drv_spi_t spi_driver = NRF_DRV_SPI_INSTANCE(2);
static nrf_drv_timer_t timer_cs = NRF_DRV_TIMER_INSTANCE(0);
static nrf_drv_timer_t timer_spi = NRF_DRV_TIMER_INSTANCE(1);
static nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
static nrf_drv_spi_xfer_desc_t xfer;
static uint16_t p_rx_data = 0x0000;
static uint8_t p_tx_data = 0xff;
static void spi_handler_test(nrf_drv_spi_evt_t const * p_event, void *p_context)
{
NRF_LOG_INFO(
"SPI_HANDLER !\n"
"read: 0x%x, 0x%x",
p_rx_data >> 8, p_rx_data & 0x00ff
);
NRF_LOG_FLUSH();
}
static void spi_setup(void)
{
nrf_ppi_channel_t ppi_channel;
uint32_t compare_evt_addr;
uint32_t spi_task_addr;
ret_code_t err_code;
// Configure SPI driver.
spi_config.ss_pin = NRF_DRV_SPI_PIN_NOT_USED;
spi_config.miso_pin = SPI_MISO_PIN;
spi_config.mosi_pin = SPI_MOSI_PIN;
spi_config.sck_pin = SPI_SCK_PIN;
// Initialize SPI driver.
err_code = nrf_drv_spi_init(&spi_driver, &spi_config, spi_handler_test, NULL);
APP_ERROR_CHECK(err_code);
// Initialize timer.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
uint32_t ticks = nrf_drv_timer_us_to_ticks(&timer_spi, 5);
err_code = nrf_drv_timer_init(&timer_spi, &timer_cfg, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_timer_extended_compare(&timer_spi, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
// Configure SPI.
xfer.p_tx_buffer = (uint8_t const *)&p_tx_data;
xfer.p_rx_buffer = (uint8_t *)&p_rx_data;
xfer.tx_length = 1;
xfer.rx_length = 2;
NRF_LOG_INFO("NRF DRIVER SPI XFER START !");
NRF_LOG_FLUSH();
err_code = nrf_drv_spi_xfer(&spi_driver, &xfer, NRF_DRV_SPI_FLAG_REPEATED_XFER | NRF_DRV_SPI_FLAG_HOLD_XFER);
NRF_LOG_INFO("NRF DRIVER SPI XFER END !");
NRF_LOG_FLUSH();
NRF_LOG_INFO("err_code = %d", err_code);
NRF_LOG_FLUSH();
APP_ERROR_CHECK(err_code);
// Get event / task addresses.
compare_evt_addr = nrf_drv_timer_event_address_get(&timer_spi, NRF_TIMER_EVENT_COMPARE0);
spi_task_addr = nrf_drv_spi_start_task_get(&spi_driver);
// Intialize PPI channel.
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, spi_task_addr);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel);
APP_ERROR_CHECK(err_code);
}
static void cs_setup(void)
{
nrf_ppi_channel_t ppi_channel;
uint32_t compare_evt_addr;
uint32_t gpiote_task_addr;
ret_code_t err_code;
// Initialize pin.
nrf_drv_gpiote_out_config_t config = GPIOTE_CONFIG_OUT_TASK_TOGGLE(false);
err_code = nrf_drv_gpiote_out_init(ADS7866_CS, &config);
APP_ERROR_CHECK(err_code);
// Initialize timer.
nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG;
uint32_t ticks = nrf_drv_timer_us_to_ticks(&timer_cs, 2);
err_code = nrf_drv_timer_init(&timer_cs, &timer_cfg, NULL);
APP_ERROR_CHECK(err_code);
nrf_drv_timer_extended_compare(&timer_cs, NRF_TIMER_CC_CHANNEL0, ticks, NRF_TIMER_SHORT_COMPARE0_CLEAR_MASK, false);
// Get event / task addresses.
compare_evt_addr = nrf_drv_timer_event_address_get(&timer_cs, NRF_TIMER_EVENT_COMPARE0);
gpiote_task_addr = nrf_drv_gpiote_out_task_addr_get(ADS7866_CS);
// Intialize PPI channel.
err_code = nrf_drv_ppi_channel_alloc(&ppi_channel);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_assign(ppi_channel, compare_evt_addr, gpiote_task_addr);
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_ppi_channel_enable(ppi_channel);
APP_ERROR_CHECK(err_code);
// Enable CS pin.
nrf_drv_gpiote_out_task_enable(ADS7866_CS);
}
/**
* @brief Function for application main entry.
*/
int main(void)
{
ret_code_t err_code;
err_code = NRF_LOG_INIT(NULL);
APP_ERROR_CHECK(err_code);
NRF_LOG_DEFAULT_BACKENDS_INIT();
err_code = nrf_drv_ppi_init();
APP_ERROR_CHECK(err_code);
err_code = nrf_drv_gpiote_init();
APP_ERROR_CHECK(err_code);
cs_setup();
spi_setup();
// Enable timers
nrf_drv_timer_enable(&timer_cs);
nrf_drv_timer_enable(&timer_spi);
while (true)
{
// Do Nothing - GPIO can be toggled without software intervention.
}
}
As you can see, the `spi_cs` is toggled correctly but the SPI does not repeat the read transaction, and we never have the event handler callback triggered.
What do we have to change to have a repeated read SPI transaction ?
Can we use only one timer with 2 differents compare channels instead of the current 2 timers ?