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 ?